home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / gui.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  101KB  |  4,302 lines

  1. /*
  2.  * $Id: gui.c,v 0.91 1994/02/20 00:53:09 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  * This file contains
  25.  *
  26.  * A. Some simple utilites, like confirmation etc.
  27.  * B. Action buttons
  28.  * C. Help facilities.
  29.  * D  Options
  30.  * E. XYPLOT
  31.  * F. Custom 4 xyplots
  32.  */
  33.  
  34. #if !defined(lint) && defined(F_ID)
  35. char *id_gui = "$Id: gui.c,v 0.91 1994/02/20 00:53:09 zhao Pre-Release $";
  36. #endif
  37.  
  38. #include <stdio.h>
  39. #include "utype.h"
  40. #include "gui.h"
  41.  
  42. /********************************************************************
  43.  * Be nasty, always install my custom colors for FORMS, otherwise
  44.  * buttons might look bad
  45.  **********************************************************************/
  46.  
  47. struct maps_
  48.   {
  49.       int indx;            /* index into forms colormap */
  50.       short r, g, b;        /* primary color values      */
  51.   };
  52.  
  53. /******************** Default colors **********************/
  54. static struct maps_ fmc[] =
  55. {
  56.     {FL_BLACK, 0, 0, 0},
  57.     {FL_RED, 255, 0, 0},
  58.     {FL_GREEN, 0, 255, 0},
  59.     {FL_YELLOW, 255, 255, 0},
  60.     {FL_BLUE, 0, 0, 255},
  61.     {FL_MAGENTA, 255, 0, 255},
  62.     {FL_CYAN, 0, 255, 255},
  63.     {FL_INACTIVE, 85, 85, 85},
  64.     {FL_WHITE, 255, 255, 255},
  65.     {FL_ORANGERED, 255, 71, 0},
  66.     {FL_INDIANRED, 198, 113, 113},
  67.     {FL_SLATEBLUE, 113, 113, 198},
  68.     {FL_GRAY68, 173, 173, 173},
  69.     {FL_GRAY76, 194, 194, 194},
  70.     {FL_GRAY91, 233, 233, 233},
  71.     {FL_GRAY92, 235, 235, 235},
  72.     {FL_GRAY12, 31, 31, 31},
  73.     {FL_DODGERBLUE, 63, 145, 255},
  74.  
  75.  /*
  76.   * following colors are used internally by forms. Need to map these too
  77.   */
  78.  
  79.     {FL_MAGIC1, 163, 163, 163},
  80.     {FL_MAGIC2, 200, 200, 200},    /* brighter */
  81.     {FL_TOP_BOUND_COL, 204, 204, 204},
  82.     {FL_LEFT_BOUND_COL, 244, 244, 244},
  83.     {FL_BOT_BOUND_COL, 91, 91, 91},
  84.     {FL_RIGHT_BOUND_COL, 40, 40, 40}
  85. };
  86.  
  87. /*******************************************************************
  88.  * Initialize forms, mostly to install default colormaps
  89.  *********************************************************************/
  90. void
  91. gui_init(void)
  92. {
  93.     struct maps_ *p = fmc, *ps = p + sizeof(fmc) / sizeof(fmc[0]);
  94.  
  95.     fl_init();
  96.  
  97.     /*
  98.      * form_single is a bit varialbe to force single buffer to test how
  99.      * panels looks on Indigoes. Not documented.
  100.      */
  101.  
  102.     fl_doublebuf = !form_single && (getgdesc(GD_BITS_NORM_DBL_BLUE) >= 3);
  103.  
  104.     while (p < ps)
  105.       {
  106.       fl_mapcolor(p->indx, p->r, p->g, p->b);
  107.       p++;
  108.       }
  109.  
  110.     /* also initialize colors for messsage panels */
  111.     set_message_color(-1, -1, -1);
  112.     reset_time();        /* to get correct time_passed() reading */
  113. }
  114.  
  115. /******************************************************************
  116.  * Some utilties based on FORMS library.
  117.  * yes_no, continue, getint etc.
  118.  ******************************************************************/
  119.  
  120. #include <stdlib.h>
  121. #include <string.h>
  122.  
  123. static void create_the_forms(void);
  124.  
  125. static const char *
  126. break_long_lines(const char *s, int n)
  127. {
  128.     static char buf[250];
  129.     char *p;
  130.  
  131.     if (!s || n < 20 || strlen(s) < n)
  132.     return s;
  133.  
  134.     Strncpy(buf, s, sizeof(buf) - 1);
  135.     if ((p = strchr(buf + n - 5, ' ')))
  136.     *p = '\n';
  137.  
  138.     return buf;
  139. }
  140.  
  141. static const char *
  142. truncate_long_lines(const char *s, int n)
  143. {
  144.     static char buf[250];
  145.  
  146.     if (!s || strlen(s) < n)
  147.     return s;
  148.  
  149.     strcpy(buf, s);
  150.     buf[n] = '\0';
  151.  
  152.     return buf;
  153. }
  154.  
  155. /****************************************************************
  156.  * Show a message and YES NO buttons
  157.  ****************************************************************/
  158. static FL_FORM *q_form;
  159. static FL_OBJECT *q_str1, *q_str2, *q_str3, *q_yes, *q_no;
  160.  
  161. int
  162. yes_no(const char *s1, const char *s2, const char *s3, int c)
  163. {
  164.     int b = 0, place = c ? FL_PLACE_CENTER : FL_PLACE_HOTSPOT;
  165.     FL_OBJECT *ret;
  166.     short val;
  167.  
  168.     create_the_forms();
  169.  
  170.     fl_set_object_label(q_str1, s1);
  171.  
  172.     /* don't want miss the messages when it is too long (clipped) */
  173.     fl_set_object_label(q_str2, truncate_long_lines(s2, 35));
  174.  
  175.     fl_set_object_label(q_str3, break_long_lines(s3, 20));
  176.  
  177.     fl_deactivate_all_forms();
  178.     bit_show_form(q_form, place, b, "Confirm");
  179.     while ((ret = fl_do_forms()) != q_no && ret != q_yes)
  180.       {
  181.       if (ret == FL_EVENT)
  182.           (void) bit_qread(&val);
  183.       }
  184.     fl_activate_all_forms();
  185.  
  186.     bit_hide_form(q_form);
  187.  
  188.     return (ret == q_yes);
  189. }
  190.  
  191. /*****************************************************************
  192.  * Show a message and  demand a mouse click
  193.  ***************************************************************/
  194.  
  195. FL_FORM *cnt_form;
  196. static FL_OBJECT *cnt_str1, *cnt_str2, *cnt_str3, *cnt_but;
  197.  
  198. void
  199. TC_continue(const char *s1, const char *s2, const char *s3, int c)
  200. {
  201.     FL_OBJECT *ret;
  202.     int b = 1, place = c ? FL_PLACE_CENTER : FL_PLACE_HOTSPOT;
  203.     short val;
  204.  
  205.     create_the_forms();
  206.     fl_set_object_label(cnt_str1, s1);
  207.     fl_set_object_label(cnt_str2, s2);
  208.     fl_set_object_label(cnt_str3, s3);
  209.  
  210.     fl_deactivate_all_forms();
  211.  
  212.     bit_show_form(cnt_form, place, b, "Pause");
  213.  
  214.     while ((ret = fl_do_forms()) != cnt_but)
  215.       {
  216.       if (ret == FL_EVENT)
  217.           (void) bit_qread(&val);
  218.       }
  219.  
  220.     bit_hide_form(cnt_form);
  221.     fl_activate_all_forms();
  222. }
  223.  
  224. /***************************************************************
  225.  * given a range, try to divided into nice steps for slider
  226.  ***************************************************************/
  227.  
  228. static void
  229. get_i_step(int r1, int r2, int *s1, int *s2)
  230. {
  231.     *s2 = (r2 - r1 + 1) / 20;
  232.  
  233.     if (*s2 > 100)
  234.     *s2 = (*s2 / 100) * 100;
  235.     else if (*s2 > 10)
  236.     *s2 = (*s2 / 10) * 10;
  237.     else if (*s2 > 4)
  238.     *s2 = 5;
  239.     else
  240.     *s2 = 2;
  241.  
  242.     if ((*s1 = *s2 / 10) < 1)
  243.     *s1 = 1;
  244. }
  245.  
  246. static FL_FORM *sinput;
  247. static FL_OBJECT *ct, *prompt, *cancel, *inok, *reset;
  248.  
  249. /*****************************************************************
  250.  * if im is set, getint will return 0 whenever there is change.
  251.  * Cancel wil return -1, while ok return 1;
  252.  *****************************************************************/
  253.  
  254. int
  255. getint(const char *p, int *in, int mini, int maxi, int im)
  256. {
  257.     int def = (maxi + mini) / 2;
  258.     int large = (maxi - mini + 1) / 20, small = 1;
  259.     int done = 0, oin = *in;    /* if im is set, oin has no meaning */
  260.     short val;
  261.     FL_OBJECT *ret;
  262.  
  263.     create_the_forms();
  264.  
  265.     get_i_step(mini, maxi, &small, &large);
  266.     fl_set_counter_bounds(ct, mini, maxi);
  267.     fl_set_counter_value(ct, *in);
  268.     fl_set_counter_step(ct, small, large);
  269.     fl_set_counter_precision(ct, 0);
  270.     fl_set_object_label(prompt, p ? p : "Integer");
  271.     fl_set_counter_return(ct, im);
  272.  
  273.     deactivate_all_forms();
  274.  
  275.     set_cursor(bit_show_form(sinput, FL_PLACE_MOUSE, 0, "Input"), CUR_HAND);
  276.  
  277.     do
  278.       {
  279.       done = ((ret = fl_do_forms()) == cancel || ret == inok);
  280.       if (ret == FL_EVENT)
  281.           (void) bit_qread(&val);
  282.       else if (ret == reset)
  283.           fl_set_counter_value(ct, def);
  284.       }
  285.     while (!done && !im);
  286.  
  287.     *in = (ret != cancel) ? fl_get_counter_value(ct) : oin;
  288.     if (done)
  289.     bit_hide_form(sinput);
  290.     fl_activate_all_forms();
  291.  
  292.     return ret == cancel ? -1 : done;
  293. }
  294.  
  295. /************************************************************
  296.  * Get a floating point number
  297.  ************************************************************/
  298. #include <math.h>
  299.  
  300. int
  301. getfloat(const char *p, float *f, float minf,
  302.      float maxf, int im, int prec)
  303. {
  304.     int def = (maxf + minf) / 2, done;
  305.     float small = 1.0 / pow(10.0, prec);
  306.     float large = small * 10;
  307.     short val;
  308.     FL_OBJECT *ret;
  309.  
  310.     create_the_forms();
  311.     fl_set_counter_bounds(ct, minf, maxf);
  312.     fl_set_counter_value(ct, *f);
  313.     fl_set_counter_step(ct, small, large);
  314.     fl_set_counter_precision(ct, prec);
  315.     fl_set_object_label(prompt, p ? p : "Float");
  316.     deactivate_all_forms();
  317.     set_cursor(bit_show_form(sinput, FL_PLACE_MOUSE, 0, "Input"), CUR_HAND);
  318.  
  319.     do
  320.       {
  321.       done = ((ret = fl_do_forms()) == cancel || ret == inok);
  322.       if (ret == FL_EVENT)
  323.           (void) bit_qread(&val);
  324.       else if (ret == reset)
  325.           fl_set_counter_value(ct, def);
  326.       }
  327.     while (!done && !im);
  328.  
  329.     if (ret != cancel)
  330.     *f = fl_get_counter_value(ct);
  331.     if (done)
  332.     bit_hide_form(sinput);
  333.     fl_activate_all_forms();
  334.  
  335.     return ret == cancel ? -1 : done;
  336. }
  337.  
  338. /*************************************************************
  339.  * Get a string from keyboard
  340.  **********************************************************{**/
  341.  
  342. static FL_FORM *input_form;
  343.  
  344. typedef void (*VStrFptr) (const char *);
  345. static VStrFptr strcb;
  346.  
  347. void
  348. set_getstring_cb(VStrFptr f)
  349. {
  350.     strcb = f;
  351. }
  352.  
  353. /* ARGSUSED */
  354. static void
  355. str_ready(FL_OBJECT * ob, long q)
  356. {
  357.     if (strcb)
  358.     strcb(fl_get_input(ob));
  359.     else
  360.     getstring_finish();
  361. }
  362.  
  363. void
  364. getstring_finish(void)
  365. {
  366.     create_the_forms();
  367.  
  368.     if (input_form->visible)
  369.       {
  370.       bit_hide_form(input_form);
  371.       fl_qenter(F1KEY, 10);
  372.       strcb = 0;
  373.       }
  374. }
  375.  
  376. /* ARGSUSED */
  377. static void
  378. str_ok_cb(FL_OBJECT * ob, long q)
  379. {
  380.     getstring_finish();
  381. }
  382.  
  383.  
  384. static FL_OBJECT *input_title;
  385. static FL_OBJECT *input_val;
  386.  
  387. const char *
  388. getstring(const char *title, const char *def, int block)
  389. {
  390.     int b = always_border;
  391.     int place = block ? FL_PLACE_HOTSPOT : FL_PLACE_SIZE;
  392.  
  393.     create_the_forms();
  394.  
  395.     if (block)
  396.     deactivate_all_forms();
  397.  
  398.     fl_set_object_label(input_title, title);
  399.     fl_set_input(input_val, def);
  400.     bit_show_form(input_form, place, b, "Input");
  401.  
  402.     if (block)
  403.       {
  404.       int strfinish;
  405.       short val;
  406.       do
  407.         {
  408.         strfinish = (fl_do_forms() == FL_EVENT) &&
  409.             (bit_qread(&val) == F1KEY && val == 10);
  410.         }
  411.       while (!strfinish);
  412.       fl_activate_all_forms();
  413.       }
  414.  
  415.     return (fl_get_input(input_val));
  416. }
  417.  
  418. /***********************************************************
  419.  * END OF getstring and associates
  420.  ********************************************************}*/
  421.  
  422. /**********************************************************/
  423.  
  424. static int llcol1 = FL_RED, llcol2 = FL_BLACK, llcol3 = FL_BLACK;
  425.  
  426. void
  427. set_message_color(int col1, int col2, int col3)
  428. {
  429.     create_the_forms();
  430.  
  431.     if (col1 >= 0)
  432.     llcol1 = col1;
  433.     if (col2 >= 0)
  434.     llcol2 = col2;
  435.     if (col3 >= 0)
  436.     llcol3 = col3;
  437.  
  438.     fl_set_object_lcol(cnt_str1, llcol1);
  439.     fl_set_object_lcol(cnt_str2, llcol2);
  440.     fl_set_object_lcol(cnt_str3, llcol3);
  441.     fl_set_object_lcol(q_str1, llcol1);
  442.     fl_set_object_lcol(q_str2, llcol2);
  443.     fl_set_object_lcol(q_str3, llcol3);
  444. }
  445.  
  446. void
  447. get_message_color(int *c1, int *c2, int *c3)
  448. {
  449.     create_the_forms();
  450.     *c1 = llcol1;
  451.     *c2 = llcol2;
  452.     *c3 = llcol3;
  453. }
  454.  
  455. /****************************************************************
  456.  * the form definations
  457.  ****************************************************************/
  458.  
  459. static void
  460. box_vert(float x, float y, float w, float h)
  461. {
  462.     long xy[2];
  463.  
  464.     xy[0] = x;
  465.     xy[1] = y + 0.5 * h;
  466.     v2i(xy);
  467.     xy[0] = x + 0.5 * w;
  468.     xy[1] = y;
  469.     v2i(xy);
  470.     xy[0] = x + w;
  471.     xy[1] = y + 0.5 * h;
  472.     v2i(xy);
  473.     xy[0] = x + 0.5 * w;
  474.     xy[1] = y + h;
  475.     v2i(xy);
  476. }
  477.  
  478. /* ARGSUSED */
  479. static int
  480. draw_box(FL_OBJECT * ob, int ev, float x, float y, char k)
  481. {
  482.  
  483.     if (ev == FL_DRAW)
  484.       {
  485.       set_current_window(ob->form->window);
  486.       reshapeviewport();
  487.  
  488.       bgnpolygon();
  489.       cpack(0xffff);
  490.       box_vert(ob->x, ob->y, ob->w, ob->h);
  491.       endpolygon();
  492.  
  493.       linewidth(2);
  494.       bgnclosedline();
  495.       cpack(0);
  496.       box_vert(ob->x, ob->y, ob->w, ob->h);
  497.       endclosedline();
  498.       linewidth(1);
  499.  
  500.       }
  501.     return 0;
  502. }
  503.  
  504. /****************************************************************
  505.  * Add a bitmap of bang ! to the message panel
  506.  ****************************************************************/
  507.  
  508. #include "bitmaps/warn.xbm"
  509. #include "bitmaps/q.xbm"
  510.  
  511. static void
  512. add_warn_icon(float x, float y, float w, float h)
  513. {
  514.     FL_OBJECT *obj;
  515.  
  516.     obj = fl_add_free(FL_SLEEPING_FREE, x, y, w, h, "", draw_box);
  517.     obj = fl_add_bitmap(FL_NORMAL_BITMAP, x, y, w, h, "");
  518.     fl_set_bitmap(obj, warn_width, warn_height, warn_bits);
  519.     fl_set_object_color(obj, 0, FL_YELLOW);
  520. }
  521.  
  522. /*****************************************************************
  523.  * Add a bitmap of question mark ? to the confirm panel
  524.  *****************************************************************/
  525. static void
  526. add_q_icon(float x, float y, float w, float h)
  527. {
  528.     FL_OBJECT *obj;
  529.  
  530.     obj = fl_add_free(FL_SLEEPING_FREE, x, y, w, h, "", draw_box);
  531.     obj = fl_add_bitmap(FL_NORMAL_BITMAP, x, y, w, h, "");
  532.     fl_set_bitmap(obj, q_width, q_height, q_bits);
  533.     fl_set_object_color(obj, 0, FL_YELLOW);
  534. }
  535.  
  536. static void
  537. create_form_sinput(void)
  538. {
  539.     FL_OBJECT *obj;
  540.  
  541.     sinput = fl_bgn_form(FL_NO_BOX, 285.0, 105.0);
  542.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 285.0, 105.0, "");
  543.     fl_set_object_color(obj, 9, 47);
  544.     ct = obj = fl_add_counter(FL_NORMAL_COUNTER, 40.0, 40.0, 200.0, 30.0, "");
  545.     fl_set_object_color(obj, 12, 4);
  546.     fl_set_object_lcol(obj, 4);
  547.     fl_set_object_lsize(obj, FL_SMALL_FONT);
  548.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  549.     prompt = obj = fl_add_text(FL_NT, 5.0, 75.0, 270.0, 20.0, "Text");
  550.     fl_set_object_lcol(obj, 4);
  551.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  552.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  553.     cancel = obj = fl_add_button(FL_NB, 100.0, 8.0, 85.0, 25.0, "Cancel");
  554.     fl_set_object_lsize(obj, 10.0);
  555.     fl_set_object_color(obj, 47, 1);
  556.     inok = obj = fl_add_button(FL_RETURN_BUTTON, 192.0, 8.0, 80.0, 25.0, "OK");
  557.     fl_set_object_lsize(obj, 10.0);
  558.     fl_set_object_color(obj, 47, 2);
  559.     reset = obj = fl_add_button(FL_NB, 10.0, 8.0, 85.0, 25.0, "Reset");
  560.     fl_set_object_lsize(obj, 10.0);
  561.     fl_set_object_color(obj, 47, 3);
  562.     fl_end_form();
  563. }
  564.  
  565. static void
  566. create_input_form(void)
  567. {
  568.     FL_OBJECT *obj;
  569.     input_form = fl_bgn_form(FL_UP_BOX, 285.0, 100.0);
  570.     input_title = obj = fl_add_text(FL_NT, 15.0, 70.0, 260.0, 20.0, "");
  571.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  572.     fl_set_object_lstyle(obj, 6);
  573.     input_val = obj = fl_add_input(FL_NI, 10.0, 40.0, 265.0, 20.0, "");
  574.     fl_set_object_boxtype(obj, FL_BORDER_BOX);
  575.     fl_set_object_color(obj, 47, 51);
  576.     fl_set_object_lsize(obj, 10.0);
  577.     fl_set_call_back(obj, str_ready, 0);
  578.     obj = fl_add_button(FL_NB, 105.0, 10.0, 60.0, 25.0, "OK");
  579.     fl_set_call_back(obj, str_ok_cb, 0);
  580.     fl_set_object_lsize(obj, 10.0);
  581.     fl_end_form();
  582.     fl_set_form_hotspot(input_form, 105 + 30, 10 + 12.5);
  583. }
  584.  
  585. static void
  586. create_yesno_form(void)
  587. {
  588.     FL_OBJECT *obj;
  589.  
  590.     q_form = fl_bgn_form(FL_UP_BOX, 300.0, 110.0);
  591.     q_str1 = obj = fl_add_box(FL_NO_BOX, 10.0, 80.0, 280.0, 20.0, "");
  592.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  593.     q_str2 = obj = fl_add_box(FL_NO_BOX, 10.0, 62.0, 280.0, 15.0, "");
  594.     fl_set_object_lsize(obj, 10.0);
  595.     q_str3 = obj = fl_add_box(FL_NO_BOX, 10.0, 42.0, 280.0, 20.0, "");
  596.     fl_set_object_lsize(obj, 10.0);
  597.  
  598.     q_no = obj = fl_add_button(FL_NB, 30.0, 10.0, 70.0, 25.0, "No");
  599.     fl_set_object_lsize(obj, 10.0);
  600.     fl_set_object_shortcut(obj, "n");
  601.     q_yes = obj = fl_add_button(FL_NB, 200.0, 10.0, 70.0, 25.0, "Yes");
  602.     fl_set_object_lsize(obj, 10.0);
  603.     fl_set_object_shortcut(obj, "y");
  604.     add_q_icon(10, 110.0 - 40, 30.0, 30.0);
  605.     fl_end_form();
  606.     fl_set_form_hotspot(q_form, 200 + 35, 10 + 12);
  607. }
  608.  
  609. static void
  610. create_cnt_form(void)
  611. {
  612.     cnt_form = fl_bgn_form(FL_UP_BOX, 420.0, 130.0);
  613.     cnt_str1 = fl_add_box(FL_NO_BOX, 10.0, 100.0, 400.0, 20.0, "");
  614.     cnt_str2 = fl_add_box(FL_NO_BOX, 10.0, 75.0, 400.0, 20.0, "");
  615.     cnt_str3 = fl_add_box(FL_NO_BOX, 10.0, 50.0, 400.0, 20.0, "");
  616.     fl_set_object_lstyle(cnt_str1, FL_BOLD_STYLE);
  617.     fl_set_object_lstyle(cnt_str2, 6);    /* Times-Roman */
  618.     fl_set_object_lstyle(cnt_str3, 6);    /* Times-Roman */
  619.     fl_set_object_lsize(cnt_str1, 11.0);
  620.     fl_set_object_lsize(cnt_str2, 11.0);
  621.     fl_set_object_lsize(cnt_str3, 11.0);
  622.     cnt_but = fl_add_button(FL_RETB, 300.0, 10.0, 105.0, 30.0, "Continue");
  623.     cnt_form->doublebuf = 0;
  624.     add_warn_icon(10.0, 130.0 - 50.0, 34.0, 34.0);
  625.     fl_end_form();
  626.     fl_set_form_hotspot(cnt_form, 300 + 53, 30);
  627. }
  628.  
  629. static void
  630. create_the_forms(void)
  631. {
  632.     static int formok;
  633.  
  634.     if (!formok)
  635.       {
  636.       create_form_sinput();
  637.       create_yesno_form();
  638.       create_cnt_form();
  639.       create_input_form();
  640.       formok = 1;
  641.       }
  642. }
  643.  
  644.  
  645. /*****************************************************************
  646.  * Actions
  647.  ****************************************************************{*/
  648.  
  649. #include <stdio.h>
  650. #include <string.h>
  651. #include "mac.h"
  652. #include "dmalloc.h"
  653.  
  654. #define MAXMACT     3        /* maximum action tables         */
  655. #define MAXSACT    10        /* maximum actin shown perscreen */
  656. #define MAXLBL     15        /* button label lenght          */
  657.  
  658. /*  structures for one action */
  659. typedef struct s_act
  660. {
  661.     struct s_act *next;        /* link                      */
  662.     int ret;            /* return value if bind is 0 */
  663.     VLfptr bind;        /* bind funciton             */
  664.     char label[MAXLBL + 1];    /* label                     */
  665. }
  666. S_ACT;
  667.  
  668. /*  action structures */
  669. typedef struct _action_t
  670.   {
  671.       int total;        /* how many are defined */
  672.       char *title;        /* title                */
  673.       char *fhelp;        /* help file name       */
  674.       S_ACT *head, *tail;    /* link                 */
  675.   }
  676. M_ACT;
  677.  
  678. static M_ACT action[MAXMACT];
  679. static void create_form_action(void);
  680.  
  681. static int do_h;        /* index in do_action */
  682.  
  683. /*
  684.  * Call back routine if any button is pressed. fake_it doesn't
  685.  * really do anything, it just lends its prototype.
  686.  */
  687. /* ARGSUSED */
  688. static void
  689. fake_it(FL_OBJECT * NotUsed, long a)
  690. {
  691.     register S_ACT *q;
  692.  
  693.     for (q = action[do_h].head; q && q->ret != a; q = q->next)
  694.     ;
  695.     if (q && q->bind)
  696.     q->bind(a);
  697. }
  698.  
  699. /********** Help ****************************/
  700. /* ARGSUSED */
  701. static void
  702. help_action(FL_OBJECT * ob, long q)
  703. {
  704.     M_ACT *p;
  705.  
  706.     p = &action[do_h];
  707.     print_help(p->fhelp, p->title, 0, 0, 0, 0);
  708. }
  709.  
  710. static int action_warn = 1;
  711.  
  712. static int
  713. bad_handle(int h)
  714. {
  715.     if (h < 0 || h >= MAXMACT)
  716.       {
  717.       M_info("Action", "Bad handle %d", h);
  718.       if (action_warn)
  719.           Bark("ActionCheckHandle", "Bad handle");
  720.       return -1;
  721.       }
  722.     return 0;
  723. }
  724.  
  725. /****************** Initialze table ************************/
  726. static void
  727. init_action(void)
  728. {
  729.     static int init;
  730.     M_ACT *act = action + MAXMACT;
  731.  
  732.     if (!init)
  733.       {
  734.       while (--act >= action)
  735.         {
  736.         act->title = act->fhelp = 0;
  737.         act->head = act->tail = 0;
  738.         act->total = 0;
  739.         }
  740.       init = 1;
  741.       }
  742. }
  743.  
  744. static int
  745. find_avail_index(void)
  746. {
  747.     int i;
  748.     static int actwarned;
  749.  
  750.     for (i = 0; i < MAXMACT; i++)
  751.       {
  752.       if (!action[i].title)
  753.           return i;
  754.       }
  755.  
  756.     /* it is in bad taste to bitch more than once */
  757.     if (!actwarned)
  758.       {
  759.       Bark("Action", "ActIndex out of bounds");
  760.       actwarned = 1;
  761.       }
  762.  
  763.     return -1;
  764. }
  765.  
  766. static void *
  767. create_new_node(size_t nbytes)
  768. {
  769.     S_ACT *p = malloc(nbytes);
  770.  
  771.     if (p)
  772.       {
  773.       p->next = 0;
  774.       p->label[0] = '\0';
  775.       }
  776.     return p;
  777. }
  778.  
  779. /*****************************************************
  780.  * Global functions to get a new table index
  781.  ****************************************************/
  782. int
  783. define_action(const char *title, const char *hfile)
  784. {
  785.     int index;
  786.     M_ACT *p;
  787.  
  788.     init_action();
  789.     create_form_action();
  790.  
  791.     if ((index = find_avail_index()) < 0)
  792.     return -1;
  793.     p = &action[index];
  794.  
  795.     p->title = strdup((title && *title) ? title : "Untitled");
  796.  
  797.     /* add help file only requested */
  798.     if (hfile && *hfile)
  799.     p->fhelp = strdup(hfile);
  800.  
  801.     p->head = p->tail = 0;
  802.     return index;
  803. }
  804.  
  805. /***************************************************************
  806.  * Add one more entries to the action table
  807.  **************************************************************/
  808. int
  809. addto_action(int handle, const char *label, VLfptr bind)
  810. {
  811.     M_ACT *p;
  812.     S_ACT *new;
  813.  
  814.     if (!label || !*label || bad_handle(handle))
  815.     return -1;
  816.  
  817.     if (!(new = create_new_node(sizeof(S_ACT))))
  818.     return -1;
  819.  
  820.     p = &action[handle];
  821.     Strncpy(new->label, label, MAXLBL);
  822.     new->bind = bind;
  823.     new->ret = p->total;
  824.  
  825.     if (!p->head)
  826.     p->head = new;
  827.     else
  828.     p->tail->next = new;
  829.  
  830.     p->tail = new;
  831.     p->total++;
  832.     return new->ret;
  833. }
  834.  
  835. /********* Free a singly-linked list **********/
  836. static void
  837. free_list(S_ACT * head)
  838. {
  839.     register S_ACT *p, *q;
  840.  
  841.     for (p = head; p; p = q)
  842.       {
  843.       q = p->next;
  844.       free(p);
  845.       }
  846. }
  847.  
  848. void
  849. free_action(int handle)
  850. {
  851.     M_ACT *p;
  852.  
  853.     if (!(handle < 0 || handle >= MAXMACT))
  854.       {
  855.       p = &action[handle];
  856.       Free(p->title);
  857.       Free(p->fhelp);
  858.       free_list(p->head);
  859.       p->head = p->tail = 0;
  860.       p->total = 0;
  861.       }
  862. }
  863.  
  864. void
  865. free_all_actions(void)
  866. {
  867.     int i;
  868.  
  869.     for (i = 0; i < MAXMACT; i++)
  870.     if (action[i].title)
  871.         free_action(i);
  872. }
  873.  
  874. /***********************************************************
  875.  * actually doing it
  876.  ***********************************************************/
  877. static int maxact;
  878. static FL_FORM *action_form;
  879. static FL_OBJECT *bact[MAXSACT], *up, *down, *end, *ahelp;
  880.  
  881. /* show action buttons. A limited no. per screen */
  882. static void
  883. load_action(S_ACT * head, int offset)
  884. {
  885.     register int i = 0;
  886.     register S_ACT *p = head;
  887.  
  888.     for (i = 0, p = head; p && i < offset; i++, p = p->next)
  889.     ;
  890.     if (!p)
  891.     return;
  892.  
  893.     fl_freeze_form(action_form);
  894.     for (i = 0; i < maxact && p; i++, p = p->next)
  895.       {
  896.       fl_show_object(bact[i]);
  897.       fl_set_object_label(bact[i], p->label);
  898.       fl_set_call_back(bact[i], fake_it, p->ret);
  899.       }
  900.  
  901.     for (; i < maxact; i++)
  902.     fl_hide_object_only(bact[i]);
  903.  
  904.     fl_unfreeze_form(action_form);
  905.     return;
  906. }
  907.  
  908. /******************************************************
  909.  * Global actiavation routine
  910.  *****************************************************/
  911. int
  912. do_action(int handle)
  913. {
  914.     int bd = 1, i = 0, done;
  915.     static int lasthandle = -1, offset;
  916.     M_ACT *p;
  917.     FL_OBJECT *ret;
  918.     short val;
  919.  
  920.     if (bad_handle(handle) || !action[handle].head)
  921.     return -1;
  922.  
  923.     create_form_action();
  924.     p = &action[handle];
  925.  
  926.     fl_set_object_label(ahelp, p->title ? p->title : "Action");
  927.  
  928.     if (lasthandle != handle)
  929.       {
  930.       offset = 0;
  931.       if (p->total < maxact)
  932.         {
  933.         fl_hide_object(up);
  934.         fl_hide_object(down);
  935.         }
  936.       else
  937.         {
  938.         fl_show_object(up);
  939.         fl_show_object(down);
  940.         }
  941.       }
  942.  
  943.     do_h = handle;
  944.     load_action(p->head, offset);
  945.     deactivate_all_forms();
  946.     bit_show_form(action_form, FL_PLACE_MOUSE, bd, "Action");
  947.     done = 0;
  948.  
  949.     do
  950.       {
  951.       ret = fl_do_forms();
  952.       if (ret == up && offset >= maxact)
  953.         {
  954.         offset -= maxact;
  955.         load_action(p->head, offset);
  956.         }
  957.       else if (ret == down && offset + maxact <= p->total)
  958.         {
  959.         offset += maxact;
  960.         load_action(p->head, offset);
  961.         }
  962.       else if (ret == end)
  963.         {
  964.         done = 1;
  965.         }
  966.       else if (ret == FL_EVENT)
  967.         {
  968.         (void) bit_qread(&val);
  969.         }
  970.       else
  971.         {
  972.         for (i = 0; i < MAXMACT; i++)
  973.             if (bact[i] == ret)
  974.             return i + offset;
  975.         }
  976.       }
  977.     while (!done);
  978.  
  979.     lasthandle = handle;
  980.     bit_hide_form(action_form);
  981.     fl_activate_all_forms();
  982.  
  983.     return 0;
  984. }
  985.  
  986. static void
  987. create_form_action(void)
  988. {
  989.     float x, y, dx, dy;
  990.     int i, j;
  991.     FL_OBJECT *obj;
  992.     static int fmade;
  993.  
  994.     if (fmade)
  995.     return;
  996.  
  997.     action_form = fl_bgn_form(FL_UP_BOX, 265.0, 295.0);
  998.     obj = fl_add_button(FL_HB, 0.0, 0.0, 265.0, 295.0, "");
  999.     fl_set_call_back(obj, help_action, 0);
  1000.  
  1001.     up = fl_add_button(FL_NB, 20.0, 10.0, 30.0, 30.0, "@8");
  1002.     fl_set_object_color(up, 47, 10);
  1003.     fl_set_object_lcol(up, 4);
  1004.     down = fl_add_button(FL_NB, 50.0, 10.0, 30.0, 30.0, "@2");
  1005.     fl_set_object_color(down, 47, 10);
  1006.     fl_set_object_lcol(down, 4);
  1007.     ahelp = fl_add_button(FL_NB, 40.0, 248.0, 184.0, 32.0, "");
  1008.     fl_set_object_boxtype(ahelp, FL_FRAME_BOX);
  1009.     fl_set_object_lsize(ahelp, 16.0);
  1010.     fl_set_object_lcol(ahelp, FL_BLUE);
  1011.     fl_set_object_lstyle(ahelp, FL_ENGRAVED_STYLE);
  1012.     fl_set_call_back(ahelp, help_action, 0);
  1013.  
  1014.     end = fl_add_button(FL_NB, 130.0, 10.0, 110.0, 30.0, "Done");
  1015.     maxact = 0;
  1016.     dx = 120.0, dy = 35.0, x = 15;
  1017.     for (j = 0, y = 200; j < MAXSACT && y > 40; j += 2, x = 15, y -= dy)
  1018.       {
  1019.       for (i = 0; i < 2; i++, x += dx)
  1020.         {
  1021.         obj = fl_add_button(FL_NB, x, y, 110.0, 30.0, "");
  1022.         fl_set_object_color(obj, 47, 1);
  1023.         bact[maxact++] = obj;
  1024.         }
  1025.       }
  1026.     fl_end_form();
  1027.     fmade = 1;
  1028. }
  1029.  
  1030. /***************************************************************
  1031.  *  END OF ACTION
  1032.  *************************************************************}*/
  1033.  
  1034.  
  1035. /******************************************************************
  1036.  * HELP facilities
  1037.  * for all help files and initialization, configuration files, the
  1038.  * program will seach System dir first.
  1039.  ***************************************************************{*/
  1040. #include <stdlib.h>
  1041.  
  1042. static void create_form_help(void);
  1043. static FL_FORM *helpfm;
  1044. static FL_OBJECT *helpdone, *hbrowser;
  1045.  
  1046. struct helps
  1047.   {
  1048.       int index;
  1049.       const char *title;    /* help title    */
  1050.       const char *fname;    /* help filename */
  1051.   };
  1052.  
  1053. /* the order is not important */
  1054. static struct helps hstruct[] =
  1055. {
  1056.     {HELP_CNTL, "ControlPanel", "cntl.hlp"},
  1057.     {HELP_COLEDIT, "Edit Color", "pixtran.hlp"},
  1058.     {HELP_COLOR, "ColorSelect", "color.hlp"},
  1059.     {HELP_CP, "Cut & Paste", "cp.hlp"},
  1060.     {HELP_CROP, "Crop", "crop.hlp"},
  1061.     {HELP_EDIT, "Editing", "edit.hlp"},
  1062.     {HELP_FSELECT, "FileSelector", "fselect.hlp"},
  1063.     {HELP_INFO, "InfoPanel", "info.hlp"},
  1064.     {HELP_LOAD, "LoadFiles", "load.hlp"},
  1065.     {HELP_LSCAN, "LinearScan", "lscan.hlp"},
  1066.     {HELP_OPTION, "SetOption", "option.hlp"},
  1067.     {HELP_ROTATE, "Rotate", "rotate.hlp"},
  1068.     {HELP_SCALE, "Scale", "scale.hlp"},
  1069.     {HELP_TEXT, "TextHelp", "text.hlp"},
  1070.     {HELP_WRITE, "SaveToDisk", "write.hlp"},
  1071.     {HELP_ZOOM, "Zoom", "zoom.hlp"},
  1072.     {HELP_QUANT, "Quantization", "quant.hlp"},
  1073.     {HELP_MARKING, "PlaceMarks", "marking.hlp"},
  1074.     {HELP_ERASER, "Simple C&P", "scp.hlp"},
  1075.     {HELP_PS, "PostScript Options", "ps.hlp"},
  1076.     {HELP_PEDIT, "Pixel Edit", "pedit.hlp"},
  1077.     {HELP_FILTER, "External Filters", "filter.hlp"},
  1078.     {HELP_CONVOLV, "External Convolution Matrix", "convolv.hlp"},
  1079.     {HELP_HIST, "Histogram Info", "hist.hlp"},
  1080.     {HELP_JPEG, "JPEG parameters", "jpeg.hlp"},
  1081.     {HELP_SMOOTH, "Smoothing", "smooth.hlp"},
  1082.     {HELP_MERGE, "ImageMerge", "merge.hlp"},
  1083.     {HELP_IBR, "ImageBrowser", "ibrowser.hlp"},
  1084.     {HELP_MPEG, "MPEG Control", "mpeg.hlp"},
  1085.     {HELP_PAINT, "PaintHelp", "paint.hlp"},
  1086.     {HELP_IBBIND, "IbrowserBinding", "ibbind.hlp"}
  1087. };
  1088.  
  1089. /***********************************************************
  1090.  * handle online help request
  1091.  **********************************************************/
  1092.  /* ARGSUSED */
  1093. void
  1094. help_cb(FL_OBJECT * nouse, long n)
  1095. {
  1096.     struct helps *h = hstruct + sizeof(hstruct) / sizeof(hstruct[0]);
  1097.  
  1098.     if (n >= 0)
  1099.       {
  1100.       /* search for the right file */
  1101.       while (--h >= hstruct && n != h->index)
  1102.           ;
  1103.       if (h < hstruct)
  1104.         {            /* can't find it */
  1105.         Bark("Help", "Bad HelpIndex");
  1106.         return;
  1107.         }
  1108.       print_help(h->fname, h->title, 0, 0, 0, 0);
  1109.       }
  1110. }
  1111.  
  1112. void
  1113. set_help_title(const char *ttt)
  1114. {
  1115.     create_form_help();
  1116.     fl_set_object_label(helpdone, ttt);
  1117. }
  1118.  
  1119. void
  1120. add_to_help(const char *line)
  1121. {
  1122.     /* add_to_help may be called before help */
  1123.     create_form_help();
  1124.     fl_add_browser_line(hbrowser, line);
  1125. }
  1126.  
  1127. void
  1128. insert_help(const char *line, int n)
  1129. {
  1130.     fl_insert_browser_line(hbrowser, n, line);
  1131. }
  1132.  
  1133. #include "extern.h"
  1134. /*** given a filename and load it into the browser ***/
  1135. void
  1136. load_help(const char *fname, const char *title)
  1137. {
  1138.     FILE *fp;
  1139.     char localstr[1024];
  1140.  
  1141.     create_form_help();
  1142.     set_help_title((title && *title) ? title : fname);
  1143.  
  1144.  
  1145.     if ((fp = get_HELPfile_fp(fname, "r")) == 0)
  1146.       {
  1147.       fl_add_browser_line(hbrowser, " ");
  1148.       sprintf(localstr, "@C1file %s not found", fname);
  1149.       fl_add_browser_line(hbrowser, localstr);
  1150.       }
  1151.     else
  1152.       {
  1153.       fclose(fp);
  1154.       strcpy(localstr, helppath);
  1155.       strcat(localstr, fname);
  1156.       fl_load_browser(hbrowser, localstr);
  1157.       }
  1158.  
  1159. #ifndef X1Y1
  1160.     {
  1161.     char moreinfo[1024];
  1162.  
  1163.     sprintf(moreinfo, infofmt, helppath);
  1164.     /* bitch about sharewhere */
  1165.     fl_add_browser_line(hbrowser, " ");
  1166.     fl_add_browser_line(hbrowser, sharewh);
  1167.     fl_add_browser_line(hbrowser, dontforget);
  1168.     fl_add_browser_line(hbrowser, moreinfo);
  1169.     fl_add_browser_line(hbrowser, " ");
  1170.  
  1171.     insert_help(" ", 1);
  1172.     insert_help(moreinfo, 1);
  1173.     insert_help(dontforget, 1);
  1174.     insert_help(sharewh, 1);
  1175.     insert_help(" ", 1);
  1176.     }
  1177.  
  1178. #endif
  1179.  
  1180. }
  1181.  
  1182. /* show a loaded browser */
  1183. void
  1184. show_help(int x, int y, int w, int h, int b)
  1185. {
  1186.     int otherfb, rcol, place;
  1187.     long rwin, cwin;
  1188.     int border = b || (always_border && (b >= 0));
  1189.  
  1190.     /* check if overlay is active */
  1191.     if ((otherfb = rubber_on_screen(&rwin, &rcol)))
  1192.       {
  1193.       set_current_window(rwin);
  1194.       rubber_hide();
  1195.       }
  1196.  
  1197.     create_form_help();
  1198.     fl_deactivate_all_forms();
  1199.  
  1200.     if (w < 0 && h < 0)
  1201.       {                /* center */
  1202.       place = FL_PLACE_CENTER;
  1203.       }
  1204.     else if (w > 200 && h > 200)
  1205.       {
  1206.       prefposition(x, x + w - 1, y, y + h - 1);
  1207.       place = FL_PLACE_FREE;
  1208.       }
  1209.     else
  1210.       {
  1211.       place = FL_PLACE_MOUSE;
  1212.       }
  1213.  
  1214.     cwin = bit_show_form(helpfm, place, border, "Help");
  1215.  
  1216.     /* now redraw overlay so that it lies under help form */
  1217.     if (otherfb)
  1218.       {
  1219.       set_current_window(rwin);
  1220.       rubber_show(rcol);
  1221.       }
  1222.  
  1223.     if (place != FL_PLACE_CENTER)
  1224.     set_current_window(cwin);
  1225. }
  1226.  
  1227. void
  1228. clear_help(void)
  1229. {
  1230.     fl_clear_browser(hbrowser);
  1231. }
  1232.  
  1233. /* ARGSUSED */
  1234. static void
  1235. finish_help(FL_OBJECT * ret, long what)
  1236. {
  1237.     bit_hide_form(helpfm);
  1238.     fl_clear_browser(hbrowser);
  1239.     fl_activate_all_forms();
  1240. }
  1241.  
  1242. /**** this is the function that should be  called ****/
  1243. void
  1244. print_help(const char *fname, const char *title, int x, int y, int w, int h)
  1245. {
  1246.     load_help(fname, title);
  1247.     show_help(x, y, w, h, always_border);
  1248. }
  1249.  
  1250. static void
  1251. create_form_help(void)
  1252. {
  1253.     FL_OBJECT *obj;
  1254.  
  1255.     if (helpfm)
  1256.     return;
  1257.  
  1258.     helpfm = fl_bgn_form(FL_NO_BOX, 535.0, 405.0);
  1259.     obj = fl_add_box(FL_DOWN_BOX, 0.0, 0.0, 535.0, 405.0, "");
  1260.     fl_set_object_color(obj, 9, 47);
  1261.     hbrowser = obj = fl_add_browser(FL_NBR, 10.0, 10.0, 510.0, 350.0, "");
  1262.     fl_set_object_boxtype(obj, FL_SHADOW_BOX);
  1263.     fl_set_object_color(obj, 53, 3);
  1264.     fl_set_browser_fontsize(obj, 11.0);
  1265.     helpdone = obj = fl_add_button(FL_NB, 140.0, 365.0, 254.0, 28.0, "");
  1266.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  1267.     fl_set_object_color(obj, 47, 2);
  1268.     fl_set_object_lcol(obj, 4);
  1269.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  1270.     fl_set_object_lsize(obj, 16.0);
  1271.     fl_set_call_back(obj, finish_help, 0);
  1272.     fl_end_form();
  1273.     fl_clear_browser(hbrowser);
  1274. }
  1275.  
  1276. /*******************************************************************
  1277.  * END OF help related routines
  1278.  ***************************************************************}*/
  1279.  
  1280.  
  1281. /*************************************************************
  1282.  * Options: multiple choices. simplar to popup except
  1283.  * we have the variable names and some brief info about
  1284.  * the meaning of the variables
  1285.  *************************************************************/
  1286. #include "dmalloc.h"
  1287. #include "mac.h"
  1288.  
  1289. #define MAXMOPT   4        /* max groups                     */
  1290. #define MAXSOPT   30        /* max questions per group        */
  1291. #define MAXCHOICE 20        /* max. no. of choices per option */
  1292. #define MAXCHL    17        /* max. lenght of a choice        */
  1293. /*
  1294.  * data structure for the option
  1295.  */
  1296. typedef struct
  1297. {
  1298.     int val, *valptr;        /* variables */
  1299.     char *vname, *what[2], *choices;    /* name, explanation, string */
  1300.     VIIpfptr cb;        /* call back routine */
  1301. }
  1302. S_OPT;
  1303.  
  1304. typedef struct
  1305.   {
  1306.       char *helpfile;
  1307.       char *title;
  1308.       int total, nosave;
  1309.       OptFunc imact;
  1310.       char *timact;
  1311.       S_OPT opt[MAXSOPT + 1];
  1312.   }
  1313. M_OPT;
  1314.  
  1315. static M_OPT options[MAXMOPT];
  1316. static M_OPT *act;
  1317. static S_OPT *copt;
  1318. static int total, offset;
  1319.  
  1320. #define MAXSN 14        /* max per screen */
  1321. static FL_FORM *opt_form;
  1322. static FL_OBJECT *optok, *ocancel, *more, *save, *load, *help;
  1323. static FL_OBJECT *imabutt;
  1324. static FL_OBJECT *choice[MAXSN], *optlabel[MAXSN], *opt[MAXSN];
  1325. static int built_in;
  1326.  
  1327. /* local functions */
  1328. static void opt_init(void);
  1329. static void fill_choices(int, int, int);
  1330. static int fill_choice(char *, int, int);
  1331. static void create_form_option(void);
  1332. static int load_save(FL_OBJECT *, int);
  1333. static int save_opt(int, const char *);
  1334. static int load_opt(int, const char *);
  1335.  
  1336. static void
  1337. opt_init(void)
  1338. {
  1339.     static int o_init;
  1340.  
  1341.     if (!o_init)
  1342.       {
  1343.       create_form_option();
  1344.       o_init = 1;
  1345.       }
  1346. }
  1347.  
  1348. /*ARGSUSED*/
  1349. static void
  1350. opt_act_cb(FL_OBJECT * q, long p)
  1351. {
  1352.     (options[p].imact) (p);
  1353. }
  1354.  
  1355. /* ARGSUSED */
  1356. static void
  1357. opt_help_cb(FL_OBJECT * q, long p)
  1358. {
  1359.     if (act->helpfile)
  1360.     print_help(act->helpfile, "", 0, 0, 0, 0);
  1361. }
  1362.  
  1363. /* ARGSUSED */
  1364. static void
  1365. opt_explain(FL_OBJECT * ha, long k)
  1366. {
  1367.     int n = k + offset;
  1368.     int c1, c2, c3;
  1369.  
  1370.     get_message_color(&c1, &c2, &c3);
  1371.     set_message_color(FL_BLUE, 0, 0);
  1372.     if (copt[n].what[0])
  1373.     TC_continue(copt[n].vname, copt[n].what[0], copt[n].what[1], 0);
  1374.     else
  1375.     TC_continue(copt[n].vname, "It is self-explanatory", "", 0);
  1376.     set_message_color(c1, c2, c3);
  1377.     return;
  1378. }
  1379.  
  1380. static int
  1381. get_newopt(const char *s)
  1382. {
  1383.     register int i;
  1384.     M_OPT *q = options;
  1385.  
  1386.     for (i = 0; i < MAXMOPT; i++, q++)
  1387.     if (!q->title || strcmp(q->title, s) == 0)
  1388.         return i;
  1389.     return -1;
  1390. }
  1391.  
  1392. static int
  1393. opt_badindex(int w)
  1394. {
  1395.     int i;
  1396.  
  1397.     if ((i = (w < 0 || w >= MAXMOPT || !options[w].title)))
  1398.     Bark("OptIndex", "Bad handle");
  1399.     return i;
  1400. }
  1401.  
  1402. /*
  1403.  * all titles are potentially file names, there should be no funny
  1404.  * characters in the title
  1405.  */
  1406. int
  1407. def_option(const char *title, int nosave, const char *hpfile)
  1408. {
  1409.     int handle;
  1410.     M_OPT *q;
  1411.  
  1412.     opt_init();
  1413.  
  1414.     /* demand a title */
  1415.     if (!title || !*title)
  1416.       {
  1417.       M_warn("Def_opt", "A title must be supplies");
  1418.       return -1;
  1419.       }
  1420.  
  1421.     if ((handle = get_newopt(title)) < 0)
  1422.     return -1;
  1423.  
  1424.     q = options + handle;
  1425.     q->helpfile = (hpfile && *hpfile) ? strdup(hpfile) : 0;
  1426.     q->title = strdup(title);
  1427.     q->total = 0;
  1428.     q->nosave = nosave;
  1429.     q->timact = 0;
  1430.  
  1431.     return handle;
  1432. }
  1433.  
  1434. int
  1435. getopt_index(const char *title)
  1436. {
  1437.     int i;
  1438.     M_OPT *q = options;
  1439.  
  1440.     if (!title)
  1441.     return -1;
  1442.  
  1443.     for (i = 0; i < MAXMOPT; i++, q++)
  1444.       {
  1445.       if (q->title && strncmp(title, q->title, strlen(q->title)) == 0)
  1446.           return i;
  1447.       }
  1448.  
  1449.     Bark("OptIndex", "%s: No such option", title);
  1450.     return -1;
  1451. }
  1452.  
  1453. int
  1454. addto_option(int ind, const char *lab, const char *expl1,
  1455.          const char *expl2, int *v, const char *choices, VIIpfptr cb)
  1456. {
  1457.     if (opt_badindex(ind) || !lab || !v || !choices)
  1458.       {
  1459.       Bark("AddtoOpt", "Bad function argument");
  1460.       return -1;
  1461.       }
  1462.  
  1463.     if (options[ind].total > MAXSOPT)
  1464.       {
  1465.       Bark("AddToOption", "MaxPerIndex out of bound");
  1466.       return -1;
  1467.       }
  1468.  
  1469.     act = &options[ind];
  1470.     copt = act->opt;
  1471.     total = act->total;
  1472.     copt += total;
  1473.     copt->vname = strdup(lab);
  1474.     copt->valptr = v;
  1475.     copt->val = *v;
  1476.     copt->choices = strdup(choices);
  1477.     copt->cb = cb;
  1478.     copt->what[0] = (expl1 && *expl1) ? strdup(expl1) : 0;
  1479.     copt->what[1] = expl2 ? strdup(expl2) : 0;
  1480.     act->total++;
  1481.  
  1482.     return total;
  1483. }
  1484.  
  1485. int
  1486. set_option_act(int n, const char *ti, OptFunc cb)
  1487. {
  1488.  
  1489.     if (opt_badindex(n) || !ti || !*ti || !cb)
  1490.     return -1;
  1491.  
  1492.     options[n].imact = cb;
  1493.     options[n].timact = strdup(ti);
  1494.  
  1495.     return 0;
  1496. }
  1497.  
  1498.  
  1499. #ifndef Free
  1500. #define Free(p) do { if(p) free(p); (p) = 0;} while (ZERO)
  1501. #endif
  1502.  
  1503. void
  1504. free_option(int ind)
  1505. {
  1506.     register S_OPT *s;
  1507.  
  1508.     if (opt_badindex(ind))
  1509.     return;
  1510.     act = &options[ind];
  1511.     copt = act->opt;
  1512.     total = act->total;
  1513.  
  1514.     for (s = copt + total; copt < s; copt++)
  1515.       {
  1516.       Free(copt->vname);
  1517.       Free(copt->what[0]);
  1518.       Free(copt->what[1]);
  1519.       Free(copt->choices);
  1520.       }
  1521.  
  1522.     Free(act->timact);
  1523.     Free(act->helpfile);
  1524.     Free(act->title);
  1525. }
  1526.  
  1527. void
  1528. free_all_options(void)
  1529. {
  1530.     int i;
  1531.     M_OPT *q = options;
  1532.  
  1533.     for (i = 0; i < MAXMOPT; i++, q++)
  1534.     if (q->title)
  1535.       {
  1536.           free_option(i);
  1537.           q->title = 0;
  1538.       }
  1539. }
  1540.  
  1541. int
  1542. do_option(int which)
  1543. {
  1544.     int i, bd = 1;
  1545.     FL_OBJECT *ret;
  1546.     short val;
  1547.  
  1548.     if (opt_badindex(which))
  1549.     return -1;
  1550.  
  1551.     act = &options[which];
  1552.     total = act->total;
  1553.     copt = act->opt;
  1554.     fl_set_object_label(help, act->title);
  1555.     (total > built_in ? fl_show_object : fl_hide_object) (more);
  1556.  
  1557.     if (act->nosave)
  1558.       {
  1559.       fl_hide_object(load);
  1560.       fl_hide_object(save);
  1561.       }
  1562.     else
  1563.       {
  1564.       fl_show_object(load);
  1565.       fl_show_object(save);
  1566.       }
  1567.  
  1568.     if (act->imact)
  1569.       {
  1570.       fl_show_object(imabutt);
  1571.       fl_set_object_label(imabutt, act->timact);
  1572.       fl_set_call_back(imabutt, opt_act_cb, which);
  1573.       }
  1574.     else
  1575.       {
  1576.       fl_hide_object(imabutt);
  1577.       }
  1578.  
  1579.     offset = 0;
  1580.  
  1581.     /*
  1582.      * update the values of the local copy as the true value might've changed
  1583.      * by means unknow to then  option routines
  1584.      */
  1585.  
  1586.     for (i = 0; i < total; i++)
  1587.     copt[i].val = *(copt[i].valptr);
  1588.  
  1589.     fill_choices(offset, total, 1);
  1590.  
  1591.     deactivate_all_forms();
  1592.     bit_show_form(opt_form, FL_PLACE_MOUSE, bd, "Options");
  1593.  
  1594.     while ((ret = fl_do_forms()) != ocancel && ret != optok)
  1595.       {
  1596.       if (ret == FL_EVENT)
  1597.           (void) bit_qread(&val);
  1598.       else
  1599.           load_save(ret, which);
  1600.       }
  1601.  
  1602.     fl_activate_all_forms();
  1603.     bit_hide_form(opt_form);
  1604.  
  1605.     if (ret == optok)
  1606.       {
  1607.       for (i = 0; i < act->total; i++)
  1608.           *(copt[i].valptr) = copt[i].val;
  1609.       }
  1610.     else
  1611.       {
  1612.       for (i = 0; i < act->total; i++)
  1613.           copt[i].val = *(copt[i].valptr);
  1614.       }
  1615.  
  1616.     for (i = 0; i < built_in; i++)
  1617.     fl_clear_choice(choice[i]);
  1618.  
  1619.     return ret == optok;
  1620. }
  1621.  
  1622. /* take str1|str2 apart and return no. of enties */
  1623. static char bufarea[MAXCHOICE][MAXCHL];
  1624. static char *chbuf[MAXCHOICE];
  1625.  
  1626. /********************************************************************
  1627.  * fill the choice with form "str1|str2...."
  1628.  * NOTE: for every call by do_option, we need to update the local
  1629.  * copies because the variable might've changed by ways unknown to
  1630.  * the option routines
  1631.  ********************************************************************/
  1632. static int
  1633. fill_choice(char *choices, int l, int update)
  1634. {
  1635.     int i, ii;
  1636.  
  1637.     if (chbuf[0] == 0)
  1638.       {
  1639.       for (i = 0; i < MAXCHOICE; i++)
  1640.           chbuf[i] = bufarea[i];
  1641.       }
  1642.  
  1643.     ii = sep_choices(choices, chbuf);
  1644.     fl_clear_choice(choice[l]);
  1645.  
  1646.     for (i = 0; i < ii; i++)
  1647.     fl_addto_choice(choice[l], chbuf[i]);
  1648.  
  1649.     if (update)
  1650.     copt[l + offset].val = *(copt[l + offset].valptr);
  1651.  
  1652.     if (copt[l + offset].val < 0 || copt[l + offset].val >= ii)
  1653.       {
  1654.       M_warn("FillChoice", "%s: BadVal %d", copt[l + offset].vname,
  1655.          copt[l + offset].val);
  1656.       *(copt[l + offset].valptr) = copt[l + offset].val =
  1657.           (copt[l + offset].val < 0) ? 0 : ii - 1;
  1658.       }
  1659.  
  1660.     fl_set_choice(choice[l], copt[l + offset].val + 1);
  1661.     return ii;
  1662. }
  1663.  
  1664. /*************************************************************
  1665.  * Fill all choices
  1666.  ************************************************************/
  1667. static void
  1668. fill_choices(int off, int all, int update)
  1669. {
  1670.     int k;
  1671.  
  1672.     fl_freeze_form(opt_form);
  1673.  
  1674.     for (k = 0; k < built_in && k + off < all; k++)
  1675.       {
  1676.       fill_choice(copt[k + off].choices, k, update);
  1677.       fl_set_object_label(optlabel[k], copt[k + off].vname);
  1678.       fl_show_object(choice[k]);
  1679.       fl_show_object(optlabel[k]);
  1680.       fl_show_object(opt[k]);
  1681.       }
  1682.  
  1683.     for (; k < built_in; k++)
  1684.       {
  1685.       fl_hide_object_only(choice[k]);
  1686.       fl_hide_object_only(opt[k]);
  1687.       fl_hide_object_only(optlabel[k]);
  1688.       }
  1689.  
  1690.     fl_unfreeze_form(opt_form);
  1691. }
  1692.  
  1693. #define OPT_MAGIC "****"
  1694. #define M_LENGTH  4
  1695. static int
  1696. save_opt(int which, const char *fn)
  1697. {
  1698.     FILE *fp;
  1699.     int all, i;
  1700.     char *ch;
  1701.  
  1702.     if (opt_badindex(which) || !fn)
  1703.     return -1;
  1704.  
  1705.     if (!(fp = msg_fopen(fn, "w")))
  1706.     return -1;
  1707.  
  1708.     act = &options[which];
  1709.     all = act->total;
  1710.  
  1711.     fprintf(fp, "%s%s\n", OPT_MAGIC, act->title);
  1712.     if (chbuf[0] == 0)
  1713.       {
  1714.       for (i = 0; i < MAXCHOICE; i++)
  1715.           chbuf[i] = bufarea[i];
  1716.       }
  1717.  
  1718.     for (i = 0; i < all; i++)
  1719.       {
  1720.       ch = act->opt[i].choices;
  1721.       (void) sep_choices(ch, chbuf);
  1722.       fprintf(fp, "%25s: %s\n", act->opt[i].vname, chbuf[act->opt[i].val]);
  1723.       }
  1724.     fclose(fp);
  1725.     return 0;
  1726.  
  1727. }
  1728.  
  1729. static int
  1730. check_optsig(FILE * fp)
  1731. {
  1732.     char line[120];
  1733.  
  1734.     if (!fgets(line, 120, fp) || strncmp(line, OPT_MAGIC, M_LENGTH))
  1735.       {
  1736.       Bark("CheckOptSig", "Not an option file");
  1737.       return -1;
  1738.       }
  1739.  
  1740.     return getopt_index(line + M_LENGTH);
  1741. }
  1742.  
  1743. /* scan the option for varaible name and its value */
  1744. #include <stdlib.h>
  1745. static int
  1746. search_choice(char *choices, char *cstr)
  1747. {
  1748.     int i, ii;
  1749.  
  1750.     if (chbuf[0] == 0)
  1751.       {
  1752.       for (i = 0; i < MAXCHOICE; i++)
  1753.           chbuf[i] = bufarea[i];
  1754.       }
  1755.  
  1756.     ii = sep_choices(choices, chbuf);
  1757.     for (i = 0; i < ii; i++)
  1758.     if (strcasecmp(chbuf[i], cstr) == 0)
  1759.         return i;
  1760.  
  1761.     return -1;
  1762. }
  1763.  
  1764. static int
  1765. search_vname(int ind, const char *vname, char *val, int set)
  1766. {
  1767.     int i, n;
  1768.     char *q;
  1769.     M_OPT *p;
  1770.  
  1771.     if (opt_badindex(ind))
  1772.     return -1;
  1773.     p = &options[ind];
  1774.     n = p->total;
  1775.     for (i = 0; i < n && strcasecmp(vname, p->opt[i].vname); i++)
  1776.     ;
  1777.     if (i >= n)
  1778.     return -1;
  1779.  
  1780.     /* now get the value */
  1781.     if ((n = search_choice(p->opt[i].choices, val)) < 0)
  1782.       {                /* did not find */
  1783.       n = strtol(val, &q, 10);    /* check if a number */
  1784.       if (val == q)        /* bad conversion */
  1785.           n = 0;
  1786.       }
  1787.     p->opt[i].val = n;
  1788.  
  1789.     if (set)
  1790.     *(p->opt[i].valptr) = n;
  1791.     return 0;
  1792. }
  1793.  
  1794. static int
  1795. load_opt_fp(FILE * fp, int set, int ind)
  1796. {
  1797.     int nerr = 0, err;
  1798.     char line[130], vname[100], val[30];
  1799.  
  1800.     while (fgets(line, sizeof(line), fp))
  1801.       {
  1802.       if (line[0] == '#' || line[0] == '!')    /* comment */
  1803.           continue;
  1804.  
  1805.       if (!(err = (sscanf(line, " %[^:]: %s ", vname, val) != 2)))
  1806.           err = search_vname(ind, vname, val, set);
  1807.       if (err)
  1808.           nerr++;
  1809.  
  1810.       if (nerr > 4)
  1811.         {
  1812.         Bark("LoadOpt", "%d errorrs encountered", nerr);
  1813.         return -1;
  1814.         }
  1815.       }
  1816.     return 0;
  1817. }
  1818.  
  1819. /*
  1820.  * Load option.
  1821.  */
  1822. int
  1823. load_optfile(const char *fn, int set)
  1824. {
  1825.     FILE *fp;
  1826.     int status1 = -1, status2 = -1, ind = -1;
  1827.  
  1828.     if (!fn)
  1829.     return -1;
  1830.  
  1831.     /* try system directory first */
  1832.     if ((fp = get_HELPfile_fp(fn, "r")) && (ind = check_optsig(fp)) >= 0)
  1833.       {
  1834.       status1 = load_opt_fp(fp, set, ind);
  1835.       M_info("LoadOpt", "SysDir %s", status1 < 0 ? "NotOk" : "OK");
  1836.       fclose(fp);
  1837.       }
  1838.  
  1839.     /* user directories */
  1840.  
  1841.     if ((fp = get_BITfile_fp(fn, "r")) && (ind = check_optsig(fp)) >= 0)
  1842.       {
  1843.       status2 = load_opt_fp(fp, set, ind);
  1844.       M_info("LoadOpt", "UserDir %s", status2 < 0 ? "NotOk" : "OK");
  1845.       fclose(fp);
  1846.       }
  1847.  
  1848.     return (status1 < 0 && status2 < 0) ? -1 : 0;
  1849. }
  1850.  
  1851.  
  1852. static int
  1853. load_opt(int ind, const char *fn)
  1854. {
  1855.     int match;
  1856.  
  1857.     if ((match = load_optfile(fn, 0)) < 0 || ind != match)
  1858.     return -1;
  1859.     act = &options[match];
  1860.     total = act->total;
  1861.     copt = act->opt;
  1862.     fill_choices(offset, total, 0);
  1863.     return 0;
  1864. }
  1865.  
  1866. static int
  1867. load_save(FL_OBJECT * but, int ind)
  1868. {
  1869.     const char *ext = "*.opt";
  1870.     char tmp[1024];
  1871.     const char *fn;
  1872.     const char *prom = (but == save) ? "Filename to Save" : "Filename to Load";
  1873.  
  1874.     sprintf(tmp, "%s.opt", act->title);
  1875.     fn = getfilename(prom, bitpath, ext, tmp, 1);
  1876.     return (but == save ? save_opt : load_opt) (ind, fn);
  1877. }
  1878.  
  1879. /*
  1880.  * call back routines
  1881.  */
  1882. static void
  1883. get_choice_cb(FL_OBJECT * c, long i)
  1884. {
  1885.     copt[i + offset].val = fl_get_choice(c) - 1;
  1886.     if (copt[i + offset].cb)
  1887.     copt[i + offset].cb(i + offset, &(copt[i + offset].val));
  1888. }
  1889.  
  1890. /* ARGSUSED */
  1891. static void
  1892. opt_nextpage_cb(FL_OBJECT * c, long a)
  1893. {
  1894.     if ((offset + built_in) < total)
  1895.     offset += built_in;
  1896.     else
  1897.     offset = 0;
  1898.     fill_choices(offset, total, 0);
  1899. }
  1900.  
  1901. static void
  1902. create_form_option(void)
  1903. {
  1904.     FL_OBJECT *obj;
  1905.     float x, y, dx, dy;
  1906.     int i;
  1907.  
  1908.     opt_form = fl_bgn_form(FL_NO_BOX, 300.0, 370.0);
  1909.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 300.0, 370.0, "");
  1910.     fl_set_object_color(obj, FL_DODGERBLUE, 47);
  1911.     obj = fl_add_button(FL_HB, 0, 0, 300.0, 370.0, "");
  1912.     fl_set_call_back(obj, opt_help_cb, HELP_OPTION);
  1913.  
  1914.     help = fl_add_button(FL_NB, 60.0, 325.0, 180.0, 30, "");
  1915.     fl_set_object_boxtype(help, FL_RSHADOW_BOX);
  1916.     fl_set_object_color(help, FL_ORANGERED, 47);
  1917.     fl_set_object_lcol(help, 4);
  1918.     fl_set_object_lstyle(help, FL_BOLD_STYLE);
  1919.     fl_set_object_lsize(obj, 14.0);
  1920.     fl_set_call_back(help, opt_help_cb, HELP_OPTION);
  1921.  
  1922.     x = 70;
  1923.     y = 45.0;
  1924.     dx = 80;
  1925.     dy = 20;
  1926.     more = fl_add_button(FL_NB, x, y, dx, dy, "More");
  1927.     fl_set_object_boxtype(more, FL_FLAT_BOX);
  1928.     fl_set_object_lcol(more, 4);
  1929.     fl_set_object_color(more, 47, FL_YELLOW);
  1930.     fl_set_object_lstyle(more, FL_ITALIC_STYLE);
  1931.     fl_set_call_back(more, opt_nextpage_cb, 0);
  1932.  
  1933.     dx += 10;
  1934.     x += dx;
  1935.     dy += 5;
  1936.     imabutt = obj = fl_add_button(FL_NB, x, y, dx, dy, "");
  1937.     fl_set_object_lsize(obj, 10.0);
  1938.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  1939.  
  1940.     dx = 165.0, dy = 20.0, x = 10, y = 295;
  1941.     for (i = 0; i < MAXSN && y > 70; i++, y -= dy, x = 10)
  1942.       {
  1943.       optlabel[i] = fl_add_text(FL_NORMAL_TEXT, x, y, dx, dy, "");
  1944.       fl_set_object_boxtype(optlabel[i], FL_FLAT_BOX);
  1945.       fl_set_object_align(optlabel[i], FL_ALIGN_RIGHT);
  1946.       fl_set_object_lsize(optlabel[i], 10.0);
  1947.       fl_set_object_lstyle(optlabel[i], FL_BOLD_STYLE);
  1948.       fl_set_object_color(optlabel[i], FL_DODGERBLUE, 22);
  1949.       opt[i] = fl_add_button(FL_HIDDEN_BUTTON, x, y, dx, dy, "");
  1950.       fl_set_call_back(opt[i], opt_explain, i);
  1951.       x += dx + 5;
  1952.       choice[i] = fl_add_choice(FL_NORMAL_CHOICE, x, y, 105.0, dy, "");
  1953.       fl_set_object_boxtype(choice[i], FL_BORDER_BOX);
  1954.       fl_set_choice_fontsize(choice[i], 10.0);
  1955.       fl_set_object_color(choice[i], 50, 0);
  1956.       fl_set_call_back(choice[i], get_choice_cb, i);
  1957.       }
  1958.     built_in = i;
  1959.  
  1960.     /* control buttons */
  1961.     dx = 70.0;
  1962.     dy = 25.0;
  1963.     x = 10.0;
  1964.     load = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Load");
  1965.     fl_set_object_lsize(obj, 10.0);
  1966.     fl_set_object_color(load, 47, FL_RED);
  1967.  
  1968.     x += dx;
  1969.     save = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Save");
  1970.     fl_set_object_lsize(obj, 10.0);
  1971.     fl_set_object_color(save, 47, FL_RED);
  1972.  
  1973.     x += dx;
  1974.     ocancel = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "Cancel");
  1975.     fl_set_object_color(ocancel, 47, FL_RED);
  1976.     fl_set_object_lsize(obj, 10.0);
  1977.  
  1978.     x += dx;
  1979.     optok = obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "OK");
  1980.     fl_set_object_lsize(obj, 10.0);
  1981.     fl_set_object_color(obj, 47, FL_GREEN);
  1982.  
  1983.     fl_end_form();
  1984.     fl_set_form_hotspot(opt_form, (x + dx / 2), (10 + dy / 2));
  1985. }
  1986.  
  1987. /*****************************************************************
  1988.  * Forms class xyplot. It is important to NOT to use dmalloc.h
  1989.  * when fully debuged. This is an ugly hack!
  1990.  ******************************************************************/
  1991. #include <stdio.h>
  1992. #include <string.h>
  1993. #include "gl/gl.h"
  1994. #include "gl/device.h"
  1995. #include "fmclient.h"
  1996. #include "gui.h"
  1997. #include "dmalloc.h"
  1998.  
  1999. #define MAXTEXT   3
  2000. #define MAXTEXTL  40
  2001. #define XEXPAND   1.02        /* expand Xmax for better tics */
  2002. #define XTEXPAND  0.5        /* expand Xmax in terms of tics */
  2003. #define YEXPAND   1.002        /* expand Ymax for better tics */
  2004. typedef struct
  2005. {
  2006.     float *x, *y;        /* the xy data            */
  2007.     int n;            /* No. of  data points    */
  2008.     float xmin, xmax;        /* x-axis extrema         */
  2009.     float ymin, ymax;        /* y-axis extrema         */
  2010.     float ax, bx;        /* x-axis scale           */
  2011.     float ay, by;        /* y-axis scale           */
  2012.     int xi, yi, xf, yf;        /* the true plotting area */
  2013.     short intpl;        /* > 1 to interpolate     */
  2014.     short within;
  2015.     short always;
  2016.     short autoxbounds;
  2017.     short autoybounds;
  2018.     short xmajor, xminor;    /* xscale info            */
  2019.     short ymajor, yminor;    /* yscale  info           */
  2020.     short p_size, c_size;
  2021.     char title[MAXTEXTL];    /* plot title             */
  2022.     char xlabel[MAXTEXTL];    /* x-axis label           */
  2023.     char ylabel[MAXTEXTL];    /* y-axis label           */
  2024.     float lsize, lstyle;    /* label size and style   */
  2025.     float csize;        /* current size           */
  2026.     float xtic, ytic, ll;    /* working                */
  2027.     short pcol, lcol;        /* plot color and lable color */
  2028.     short vert[MAXTEXT];    /* direction */
  2029.     short tcol[MAXTEXT];
  2030.     short tstyle[MAXTEXT];
  2031.     float tsize[MAXTEXT];
  2032.     float tx[MAXTEXT], ty[MAXTEXT];
  2033.     char text[MAXTEXT][MAXTEXTL];
  2034. }
  2035. Plot_h;
  2036.  
  2037.  
  2038. typedef Plot_h SPEC;
  2039.  
  2040. enum
  2041.   {
  2042.       LS_SOLID,
  2043.       LS_DASHED,
  2044.       LS_DOTTED,
  2045.       LS_LINEPOINT,
  2046.       LS_EMPTY
  2047.   };
  2048.  
  2049. #define P_SIZE 3        /* square      */
  2050. #define C_SIZE 4        /* circle size */
  2051.  
  2052. static int p_size, c_size;
  2053. static fmfonthandle thefont[5];
  2054.  
  2055. static void do_xyplot_tics(Plot_h *);
  2056.  
  2057. static void
  2058. init_ls(void)
  2059. {
  2060.     static int ok;
  2061.  
  2062.     if (!ok)
  2063.       {
  2064.       deflinestyle(LS_DASHED, 0x00ff);
  2065.       deflinestyle(LS_DOTTED, 0x0180);
  2066.       deflinestyle(LS_LINEPOINT, 0xe187);
  2067.       deflinestyle(LS_EMPTY, 0);
  2068.       thefont[0] = fmfindfont(FL_FONT_NAME_0);
  2069.       thefont[1] = fmfindfont(FL_FONT_NAME_1);
  2070.       thefont[2] = fmfindfont(FL_FONT_NAME_2);
  2071.       thefont[3] = fmfindfont(FL_FONT_NAME_3);
  2072.       thefont[4] = fmfindfont(FL_FONT_NAME_4);
  2073.       }
  2074. }
  2075.  
  2076. static void
  2077. Line(float xi, float yi, float xf, float yf)
  2078. {
  2079.     float ic1[2], ic2[2];
  2080.     ic1[0] = xi;
  2081.     ic1[1] = yi;
  2082.     ic2[0] = xf;
  2083.     ic2[1] = yf;
  2084.     bgnline();
  2085.     v2f(ic1);
  2086.     v2f(ic2);
  2087.     endline();
  2088. }
  2089.  
  2090. static void
  2091. vv(float x, float y)
  2092. {
  2093.     float ff[2];
  2094.     ff[0] = x;
  2095.     ff[1] = y;
  2096.     v2f(ff);
  2097. }
  2098.  
  2099. static float gen_tic(float, float, int, int);
  2100.  
  2101. static void
  2102. get_min_max(float *a, int n, float *fmin, float *fmax)
  2103. {
  2104.     register float fi, fm, *f = a, *fend;
  2105.  
  2106.     fi = a[0];
  2107.     fm = a[0];
  2108.  
  2109.     for (fend = f + n; f < fend; f++)
  2110.       {
  2111.       if (fi > *f)
  2112.           fi = *f;
  2113.       if (fm < *f)
  2114.           fm = *f;
  2115.       }
  2116.  
  2117.     *fmin = fi;
  2118.     *fmax = fm;
  2119. }
  2120.  
  2121. static hchar, wchar;
  2122. static void
  2123. draw_vert_text(int align, float x, float y, char *text,
  2124.            int col, float size, int style)
  2125. {
  2126.     fmfonthandle t;
  2127.     double pagematrix[3][2];
  2128.     int w;
  2129.  
  2130.     t = fmscalefont(thefont[style], size);
  2131.     w = fmgetstrwidth(t, text);
  2132.     fmsetfont(t);
  2133.     fmgetpagematrix(pagematrix);
  2134.     fmrotatepagematrix(90.0);
  2135.     switch (align)
  2136.       {
  2137.       case FL_ALIGN_TOP:
  2138.       x -= (0.5 * hchar);
  2139.       y -= w;
  2140.       break;
  2141.       case FL_ALIGN_BOTTOM:
  2142.       x -= (0.5 * hchar);
  2143.       break;
  2144.       case FL_ALIGN_LEFT:
  2145.       y -= (0.5 * w);
  2146.       x += hchar;
  2147.       break;
  2148.       case FL_ALIGN_RIGHT:
  2149.       y -= (0.5 * w);
  2150.       break;
  2151.       case FL_ALIGN_CENTER:
  2152.       default:
  2153.       x += (0.5 * hchar);
  2154.       y -= (0.5 * w);
  2155.       break;
  2156.       }
  2157.     cmov2i(x, y);
  2158.     fl_color(col);
  2159.     fmprstr(text);
  2160.     fmsetpagematrix(pagematrix);
  2161. }
  2162.  
  2163. static void
  2164. draw_xyplot_text(FL_OBJECT * ob, int clr)
  2165. {
  2166.     int i, c;
  2167.     float fx, fy;
  2168.     Plot_h *p = (Plot_h *) ob->spec;
  2169.  
  2170.     set_current_window(ob->form->window);
  2171.     for (i = 0; i < MAXTEXT; i++)
  2172.       {
  2173.       if (!p->text[i][0])
  2174.           continue;
  2175.       fx = p->ax * p->tx[i] + p->bx;
  2176.       fy = p->ay * p->ty[i] + p->by;
  2177.       c = clr ? ob->col1 : p->tcol[i];
  2178.       if (p->vert[i])
  2179.         {
  2180.         draw_vert_text(FL_ALIGN_CENTER, fx, fy, p->text[i], c,
  2181.                    p->tsize[i], p->tstyle[i]);
  2182.         }
  2183.       else
  2184.         {
  2185.         fl_drw_text_beside(FL_ALIGN_CENTER, fx, fy, 0, 0,
  2186.                    c, p->tsize[i], p->tstyle[i], p->text[i]);
  2187.         }
  2188.       }
  2189. }
  2190.  
  2191. /***************************************************************
  2192.  * this routine does the XYplot, including arbitary text
  2193.  * Purposely not using hardware clipping, scrmask,  because we
  2194.  * want clamp the max. It does not take care of lables etc
  2195.  * which fl_redraw_object will take care.
  2196.  *************************************************************/
  2197. static void
  2198. doit(int s, FL_OBJECT * ob)
  2199. {
  2200.     Plot_h *p = (Plot_h *) ob->spec;
  2201.     float fx, fy, fyy, fx1, fy1;
  2202.     float *x = p->x, *y = p->y, ymin = p->ymin, vymax, vymin;
  2203.     float ax = p->ax, ay = p->ay, bx = p->bx, by = p->by;
  2204.     int n1 = 0, n = p->n;
  2205.     int i;
  2206.     long ostyle = getlstyle();
  2207.  
  2208.     /* rid of out of range data */
  2209.     while (n1 < n && (p->x[n1] < 0.9 * p->xmin))
  2210.     n1++;
  2211.     while (n > 1 && (p->x[n - 1] > 1.1 * p->xmax))
  2212.     n--;
  2213.     vymax = ay * (1.1 * p->ymax) + by;
  2214.     vymin = ay * (0.9 * p->ymin) + by;
  2215.  
  2216.     set_current_window(ob->form->window);
  2217.     reshapeviewport();
  2218.     fl_color(p->pcol);
  2219.     switch (s)
  2220.       {
  2221.       case FL_LINE_XYPLOT:
  2222.       setlinestyle(0);
  2223.       break;
  2224.       case FL_DASHED_XYPLOT:
  2225.       setlinestyle(LS_DASHED);
  2226.       break;
  2227.       case FL_DOTTED_XYPLOT:
  2228.       setlinestyle(LS_DOTTED);
  2229.       break;
  2230.       case FL_LINEPOINT_XYPLOT:
  2231.       setlinestyle(LS_LINEPOINT);
  2232.       break;
  2233.       case FL_POINTS_XYPLOT:
  2234.       bgnpoint();
  2235.       for (i = n1; i < n; i++)
  2236.         {
  2237.         fx = ax * x[i] + bx;
  2238.         fy = ay * y[i] + by;
  2239.         Range(fy, vymin, vymax);
  2240.         vv(fx - 1, fy);
  2241.         vv(fx, fy);
  2242.         vv(fx + 1, fy);
  2243.         vv(fx, fy - 1);
  2244.         vv(fx, fy + 1);
  2245.         }
  2246.       endpoint();
  2247.       setlinestyle(LS_EMPTY);
  2248.       break;
  2249.       case FL_SQUARE_XYPLOT:
  2250.       case FL_LINESQUARE_XYPLOT:
  2251.       case FL_ACTIVE_XYPLOT:
  2252.       setlinestyle(0);
  2253.       if (p_size)
  2254.         {
  2255.         for (i = n1; i < n; i++)
  2256.           {
  2257.               fx = ax * x[i] + bx;
  2258.               fy = ay * y[i] + by;
  2259.               Range(fy, vymin, vymax);
  2260.               rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
  2261.           }
  2262.         }
  2263.       setlinestyle(s == FL_SQUARE_XYPLOT ? LS_EMPTY : 0);
  2264.       break;
  2265.       case FL_CIRCLE_XYPLOT:
  2266.       case FL_LINECIRCLE_XYPLOT:
  2267.       setlinestyle(0);
  2268.       for (i = n1; i < n; i++)
  2269.         {
  2270.         fx = ax * x[i] + bx;
  2271.         fy = ay * y[i] + by;
  2272.         Range(fy, vymin, vymax);
  2273.         circ(fx, fy, c_size);
  2274.         }
  2275.       setlinestyle(s == FL_CIRCLE_XYPLOT ? LS_EMPTY : 0);
  2276.       break;
  2277.       case FL_IMPULSE_XYPLOT:
  2278.       case FL_IMPULSELINE_XYPLOT:
  2279.       setlinestyle(0);
  2280.       fyy = ay * ymin + by;
  2281.       for (i = n1; i < n; i++)
  2282.         {
  2283.         fx = ax * x[i] + bx;
  2284.         fy = ay * y[i] + by;
  2285.         Range(fy, vymin, vymax);
  2286.         Line(fx, fyy, fx, fy);
  2287.         }
  2288.       setlinestyle(s == FL_IMPULSE_XYPLOT ? LS_EMPTY : 0);
  2289.       break;
  2290.       case FL_LINEFILL_XYPLOT:
  2291.       setlinestyle(0);
  2292.       fyy = ay * ymin + by;
  2293.       for (i = n1; i < n - 1; i++)
  2294.         {
  2295.         fx = ax * x[i] + bx;
  2296.         fy = ay * y[i] + by;
  2297.         Range(fy, vymin, vymax);
  2298.         fx1 = ax * x[i + 1] + bx;
  2299.         fy1 = ay * y[i + 1] + by;
  2300.         Range(fy1, vymin, vymax);
  2301.         bgnpolygon();
  2302.         vv(fx, fyy);
  2303.         vv(fx, fy);
  2304.         vv(fx1, fy1);
  2305.         vv(fx1, fyy);
  2306.         endpolygon();
  2307.         }
  2308.       setlinestyle(LS_EMPTY);
  2309.       break;
  2310.       default:
  2311.       setlinestyle(0);
  2312.       break;
  2313.       }
  2314.     /* the bounding rectangle */
  2315.     s = getlstyle();
  2316.     setlinestyle(0);
  2317.     fl_color(p->lcol);
  2318.     recti(p->xi, p->yi, p->xf, p->yf);
  2319.  
  2320.     /* the final drawing */
  2321.  
  2322.     if (s != LS_EMPTY)
  2323.       {
  2324.       setlinestyle(s);
  2325.       fl_color(p->pcol);
  2326.       bgnline();
  2327.       for (i = n1; i < n; i++)
  2328.         {
  2329.         fx = ax * x[i] + bx;
  2330.         fy = ay * y[i] + by;
  2331.         Range(fy, vymin, vymax);
  2332.         vv(fx, fy);
  2333.         }
  2334.       endline();
  2335.       }
  2336.  
  2337.     /* additional text */
  2338.     draw_xyplot_text(ob, 0);
  2339.     setlinestyle(ostyle);    /* restore the old style */
  2340. }
  2341.  
  2342. static void
  2343. nice_label(float tic, int minor, float f, char label[])
  2344. {
  2345.     float crit = tic * minor;
  2346.  
  2347.     if (tic > 1.0 && crit < 1000.0)
  2348.     sprintf(label, "%.0f", f);
  2349.     else if (crit >= 0.48 && crit <= 999.0)
  2350.     sprintf(label, "%.1f", f);
  2351.     else if (crit < 0.48 && crit >= 0.01)
  2352.     sprintf(label, "%.2f", f);
  2353.     else if (crit >= 1000.0)
  2354.     sprintf(label, "%.0g", f);
  2355.     else
  2356.     sprintf(label, "%g", f);
  2357. }
  2358.  
  2359. static void
  2360. print_xtics(Plot_h * p)
  2361. {
  2362.     register float xw, xr, xmin = p->xmin, xmax = p->xmax;
  2363.     register int minor = p->xminor;
  2364.     register float ax = p->ax, bx = p->bx;
  2365.     float tic = p->xtic, ll = p->ll;
  2366.     int yi = p->yi;
  2367.     char label[120];
  2368.  
  2369.     xmin = ((int) (xmin / tic)) * tic;
  2370.     xmax *= XEXPAND;
  2371.     xmax += XTEXPAND * tic;
  2372.     xw = xmin;
  2373.  
  2374.     fl_color(p->lcol);
  2375.     while (xw <= xmax)
  2376.       {
  2377.       xr = ax * xw + bx;
  2378.       Line(xr, yi - ll, xr, yi - 1);
  2379.       nice_label(tic, minor, xw, label);
  2380.       fl_drw_text(FL_ALIGN_TOP, xr, yi - ll + 2, 0.0, 0,
  2381.               p->lcol, p->csize, p->lstyle, label);
  2382.       xw += tic * minor;
  2383.       }
  2384.  
  2385.     /* minor tics */
  2386.     xw = xmin;
  2387.     while (xw <= xmax)
  2388.       {
  2389.       xr = ax * xw + bx;
  2390.       Line(xr, yi, xr, yi - ll / 2);
  2391.       xw += tic;
  2392.       }
  2393. }
  2394.  
  2395. static void
  2396. print_ytics(Plot_h * p)
  2397. {
  2398.     register float yw, yr, ymin = p->ymin, ymax = p->ymax;
  2399.     register float ay = p->ay, by = p->by;
  2400.     register int minor = p->yminor;
  2401.     float tic = p->ytic, ll = p->ll;
  2402.     int xi = p->xi;
  2403.     char label[120];
  2404.  
  2405.     fl_color(p->lcol);
  2406.     ymax *= YEXPAND;
  2407.     yw = ymin;
  2408.  
  2409.     while (yw <= ymax)
  2410.       {
  2411.       yr = ay * yw + by;
  2412.       Line(xi - ll, yr, xi, yr);
  2413.       nice_label(tic, minor, yw, label);
  2414.       fl_drw_text(FL_ALIGN_RIGHT, xi - ll + 2, yr,
  2415.               0.0, 0.0, p->lcol, p->csize, p->lstyle, label);
  2416.       yw += tic * minor;
  2417.       }
  2418.  
  2419.     /* minor tics */
  2420.  
  2421.     fl_color(p->lcol);
  2422.     yw = ymin;
  2423.     while (yw <= ymax)
  2424.       {
  2425.       yr = ay * yw + by;
  2426.       Line(xi - ll / 2, yr, xi, yr);
  2427.       yw += tic;
  2428.       }
  2429. }
  2430.  
  2431. #define LL 8
  2432. static void
  2433. get_char_size(int *w, int *h, float size, int style)
  2434. {
  2435.     *h = fl_get_char_height(size, style);
  2436.     *w = fl_get_string_width(size, style, "W");
  2437. }
  2438.  
  2439. static void
  2440. get_xyplot_bounds(SPEC * p)
  2441. {
  2442.     /* get min and max */
  2443.     if (p->autoxbounds)
  2444.     get_min_max(p->x, p->n, &(p->xmin), &(p->xmax));
  2445.     if (p->autoybounds)
  2446.     get_min_max(p->y, p->n, &(p->ymin), &(p->ymax));
  2447.     /* take care of  horizonal line */
  2448.     if ((p->ymax - p->ymin) <= 1.e-6)
  2449.       {
  2450.       p->ymin -= 1.0;
  2451.       p->ymax += 1.0;
  2452.       }
  2453. }
  2454.  
  2455. static void
  2456. draw_xyplot(FL_OBJECT * ob)
  2457. {
  2458.     Plot_h *sp = (Plot_h *) ob->spec;
  2459.     float xmin, xmax;
  2460.     float ymin, ymax;
  2461.     float xoff1, xoff2, yoff1, yoff2;
  2462.     float xi, yi, xf, yf, xtic, ytic;
  2463.     int ll;
  2464.     int cc;
  2465.     char tmp[12];
  2466.  
  2467.     if (sp->n <= 0 || !sp->x || !sp->y)
  2468.     return;
  2469.  
  2470.     init_ls();
  2471.  
  2472.     get_xyplot_bounds(sp);
  2473.     xmin = sp->xmin;
  2474.     xmax = sp->xmax;
  2475.     ymin = sp->ymin;
  2476.     ymax = sp->ymax;
  2477.  
  2478.     fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, FL_CHART_BW);
  2479.     fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  2480.                ob->lcol, ob->lsize, ob->lstyle, ob->label);
  2481.  
  2482.     /* sort of auto-adjust */
  2483.     if (ob->h > 500 || ob->w > 500)
  2484.     ll = (LL + ob->w / 500);
  2485.     else if (ob->w <= 100 || ob->h <= 100)
  2486.     ll = LL - 2;
  2487.     else
  2488.     ll = LL;
  2489.  
  2490.     sp->ll = ll;
  2491.     sp->csize = sp->lsize;
  2492.     if ((ob->h <= 80. || ob->w <= 80.) && sp->lsize >= FL_SMALL_FONT)
  2493.       {
  2494.       sp->csize = FL_SMALL_FONT - 2;
  2495.       }
  2496.     else if ((ob->h >= 250 || ob->w >= 250) && (sp->lsize <= FL_SMALL_FONT))
  2497.       {
  2498.       sp->csize = FL_SMALL_FONT + 2;
  2499.       }
  2500.  
  2501.     p_size = sp->p_size;
  2502.     c_size = sp->c_size;
  2503.  
  2504.     if (ob->h > 400 && ob->w > 400 && sp->p_size && sp->c_size)
  2505.       {
  2506.       p_size++;
  2507.       c_size++;
  2508.       }
  2509.  
  2510.     xmax *= XEXPAND;
  2511.     ymax *= YEXPAND;
  2512.     sp->xtic = xtic = (sp->xmajor <= 0 || sp->xminor < 0) ? -1.0 :
  2513.     gen_tic(xmin, xmax, sp->xmajor, sp->xminor);
  2514.     sp->ytic = ytic = (sp->ymajor <= 0 || sp->yminor < 0) ? -1.0 :
  2515.     gen_tic(ymin, ymax, sp->ymajor, sp->yminor);
  2516.  
  2517.     get_char_size(&wchar, &hchar, sp->csize, sp->lstyle);
  2518.  
  2519.     /**** calculate space for title, tic marks etc ****/
  2520.  
  2521.     cc = C_SIZE / 2;
  2522.     yoff1 = yoff2 = xoff1 = xoff2 = sp->p_size + 2;
  2523.  
  2524.     /* get xoff1 */
  2525.     if (ytic > 0.0)
  2526.       {
  2527.       nice_label(ytic, sp->yminor, sp->ymax, tmp);
  2528.       xoff1 += (fl_get_string_width(sp->csize, sp->lstyle, tmp) + ll);
  2529.       }
  2530.  
  2531.     xoff1 += (sp->ylabel[0] ? hchar : 1) + cc;
  2532.  
  2533.     /* get xoff2. */
  2534.     if (xtic > 0.0)
  2535.       {
  2536.       nice_label(ytic, sp->yminor, sp->xmax, tmp);
  2537.       xoff2 += (0.6 * fl_get_string_width(sp->csize, sp->lstyle, tmp));
  2538.       xmax += XTEXPAND * xtic;
  2539.       }
  2540.  
  2541.     /* yoff1  */
  2542.     yoff1 += (xtic > 0.0) ? (ll + hchar + 1) : 0;
  2543.     yoff1 += (sp->xlabel[0] ? hchar : 1) + cc;
  2544.  
  2545.     /* yoff2 */
  2546.     yoff2 += (sp->title[0] ? (1.5 * hchar) : 1) + cc;
  2547.  
  2548.     sp->xi = xi = (ob->x + xoff1);
  2549.     sp->yi = yi = (ob->y + yoff1);
  2550.     sp->xf = xf = (ob->x + ob->w - xoff2);
  2551.     sp->yf = yf = (ob->y + ob->h - yoff2);
  2552.  
  2553.     sp->ax = (xf - xi) / (xmax - xmin);
  2554.     sp->bx = xi - sp->ax * xmin;
  2555.     sp->ay = (yf - yi) / (ymax - ymin);
  2556.     sp->by = yi - sp->ay * ymin;
  2557.  
  2558.     doit(ob->type, ob);
  2559.  
  2560.     /* generate tic marks only if requested */
  2561.     do_xyplot_tics(sp);
  2562.  
  2563.     draw_vert_text(FL_ALIGN_LEFT, ob->x + 1, (yi + yf) * 0.5, sp->ylabel,
  2564.            sp->lcol, sp->csize, sp->lstyle);
  2565.     fl_drw_text(FL_ALIGN_BOTTOM, (xi + xf) * 0.5, ob->y + 2, 0.0, 0.0,
  2566.         sp->lcol, sp->csize, sp->lstyle, sp->xlabel);
  2567.     fl_drw_text(FL_ALIGN_BOTTOM, (xi + xf) * 0.5, yf + 2, 0.0, 0.0,
  2568.         sp->lcol, sp->csize, sp->lstyle, sp->title);
  2569. }
  2570.  
  2571. /* ARGSUSED */
  2572. static void
  2573. free_xyplot(Plot_h * p)
  2574. {
  2575.     if (!p)
  2576.     return;
  2577.     if (p->x)
  2578.     free(p->x);
  2579.     if (p->y)
  2580.     free(p->y);
  2581.     free(p);
  2582.     p->x = p->y = 0;
  2583. }
  2584.  
  2585. #ifndef Abs
  2586. #define Abs(a) ((a)>0 ? (a):-(a))
  2587. #endif
  2588.  
  2589. /******* handle active_ xyplot mouse position change ********/
  2590.  
  2591. static void
  2592. redraw_point(Plot_h * p, int i, int clr)
  2593. {
  2594.     float vymax = p->ay * (1.1 * p->ymax) + p->by;
  2595.     float vymin = p->ay * (0.9 * p->ymin) + p->by;
  2596.     float fx, fy, ofx, ofy;
  2597.  
  2598.     ofx = fx = p->ax * p->x[i] + p->bx;
  2599.     ofy = fy = p->ay * p->y[i] + p->by;
  2600.     Range(fy, vymin, vymax);
  2601.  
  2602.     if (p_size)
  2603.     rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
  2604.  
  2605.     /* draw the nearest neighbors only if not clearing */
  2606.     if (!clr)
  2607.       {
  2608.       if (i > 0 && p_size)
  2609.         {
  2610.         fx = p->ax * p->x[i - 1] + p->bx;
  2611.         fy = p->ay * p->y[i - 1] + p->by;
  2612.         rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
  2613.         }
  2614.  
  2615.       if (i < p->n - 1 && p_size)
  2616.         {
  2617.         fx = p->ax * p->x[i + 1] + p->bx;
  2618.         fy = p->ay * p->y[i + 1] + p->by;
  2619.         rect(fx - p_size, fy - p_size, fx + p_size, fy + p_size);
  2620.         }
  2621.       }
  2622.  
  2623.     /* and connecting lines */
  2624.     bgnline();
  2625.  
  2626.     if (i > 1 && !clr)        /* next neibgor */
  2627.       {
  2628.       fx = p->ax * p->x[i - 2] + p->bx;
  2629.       fy = p->ay * p->y[i - 2] + p->by;
  2630.       vv(fx, fy);
  2631.       }
  2632.  
  2633.     if (i > 0)
  2634.       {
  2635.       fx = p->ax * p->x[i - 1] + p->bx;
  2636.       fy = p->ay * p->y[i - 1] + p->by;
  2637.       vv(fx, fy);
  2638.       }
  2639.  
  2640.     vv(ofx, ofy);
  2641.  
  2642.     if (i < p->n - 1)
  2643.       {
  2644.       fx = p->ax * p->x[i + 1] + p->bx;
  2645.       fy = p->ay * p->y[i + 1] + p->by;
  2646.       vv(fx, fy);
  2647.       }
  2648.  
  2649.     if (i < (p->n - 2) && !clr)
  2650.       {
  2651.       fx = p->ax * p->x[i + 2] + p->bx;
  2652.       fy = p->ay * p->y[i + 2] + p->by;
  2653.       vv(fx, fy);
  2654.       }
  2655.     endline();
  2656. }
  2657.  
  2658. static void
  2659. do_xyplot_tics(Plot_h * p)
  2660. {
  2661.     if (p->xtic > 0.0)
  2662.     print_xtics(p);
  2663.     if (p->ytic > 0.0)
  2664.     print_ytics(p);
  2665. }
  2666.  
  2667. static void
  2668. draw_changed_part(FL_OBJECT * ob, int i, float x, float y)
  2669. {
  2670.     Plot_h *sp = (Plot_h *) ob->spec;
  2671.  
  2672.     if (ob->form->doublebuf)
  2673.       {
  2674.       sp->x[i] = x;
  2675.       sp->y[i] = y;
  2676.       fl_redraw_object(ob);
  2677.       }
  2678.     else
  2679.       {
  2680.       set_current_window(ob->form->window);
  2681.       /* clear old drawing */
  2682.       fl_color(ob->col1);
  2683.       redraw_point(sp, i, 1);
  2684.  
  2685.       /* make the bounding */
  2686.       fl_color(sp->lcol);
  2687.       recti(sp->xi, sp->yi, sp->xf, sp->yf);
  2688.  
  2689.       /* draw the new point */
  2690.       sp->x[i] = x;
  2691.       sp->y[i] = y;
  2692.       fl_color(sp->pcol);
  2693.       redraw_point(sp, i, 0);
  2694.       do_xyplot_tics(sp);
  2695.       }
  2696. }
  2697.  
  2698. static int
  2699. handle_mouse(FL_OBJECT * ob, float mx, float my)
  2700. {
  2701.     SPEC *sp = (SPEC *) ob->spec;
  2702.     int i, found = 0;
  2703.     float x, y, deltax, deltay, dx, dy;
  2704.     static float lmx, lmy;
  2705.  
  2706.     if (lmx == mx && lmy == my)
  2707.       {
  2708.       if (sp->within)
  2709.           set_cursor(ob->form->window, CUR_S_CROSS);
  2710.       return 0;
  2711.       }
  2712.  
  2713.     lmx = mx;
  2714.     lmy = my;
  2715.  
  2716.     deltax = (float) (p_size ? p_size : P_SIZE) / (sp->ax);
  2717.     deltay = (float) (p_size ? p_size : P_SIZE) / (sp->ay);
  2718.     deltax = Abs(deltax);
  2719.     deltay = Abs(deltax);
  2720.  
  2721.     x = (mx - sp->bx) / (sp->ax);
  2722.     y = (my - sp->by) / (sp->ay);
  2723.     if (sp->within <= 0)
  2724.       {
  2725.       /* see which points it is on, binary search ? */
  2726.       for (i = 0; i < sp->n && !found; i++)
  2727.         {
  2728.         dx = x - sp->x[i];
  2729.         dy = y - sp->y[i];
  2730.         found = ((Abs(dx) <= deltax) && (Abs(dy) <= deltay));
  2731.         }
  2732.       if ((sp->within = (found ? i : 0)))
  2733.           set_cursor(ob->form->window, CUR_S_CROSS);
  2734.       return 0;
  2735.       }
  2736.  
  2737.     i = sp->within - 1;
  2738.     if (y > sp->ymax)
  2739.     y = sp->ymax;
  2740.     else if (y < sp->ymin)
  2741.     y = sp->ymin;
  2742.  
  2743.     if (x < sp->xmin)
  2744.     x = sp->xmin;
  2745.     else if (x > sp->xmax)
  2746.     x = sp->xmax;
  2747.  
  2748.     /* first and last points must not allow to change */
  2749.     if (i == 0 || i == sp->n - 1)
  2750.       {
  2751.       x = sp->x[i];
  2752.       }
  2753.     else
  2754.       {
  2755.       if (x >= sp->x[i + 1])
  2756.           x = (0.99 * sp->x[i + 1]);
  2757.       else if (x <= sp->x[i - 1])
  2758.           x = (1.01 * sp->x[i - 1]);
  2759.       }
  2760.     draw_changed_part(ob, i, x, y);
  2761.     sp->x[i] = x;
  2762.     sp->y[i] = y;
  2763.     return sp->always;
  2764. }
  2765.  
  2766. /* ARGSUSED */
  2767. static int
  2768. handle_it(FL_OBJECT * ob, int event, float mx, float my, char k)
  2769. {
  2770.     int ret = 0;
  2771.     switch (event)
  2772.       {
  2773.       case FL_DRAW:
  2774.       draw_xyplot(ob);
  2775.       break;
  2776.       case FL_PUSH:
  2777.       case FL_MOUSE:
  2778.       ret = handle_mouse(ob, mx, my);
  2779.       break;
  2780.       case FL_RELEASE:
  2781.       if (((SPEC *) ob->spec)->within > 0)
  2782.           ((SPEC *) ob->spec)->within *= -1;
  2783.       ret = !((SPEC *) ob->spec)->always;
  2784.       set_cursor(ob->form->window, CUR_DEFAULT);
  2785.       break;
  2786.       case FL_FREEMEM:
  2787.       free_xyplot((Plot_h *) ob->spec);
  2788.       break;
  2789.       }
  2790.     return ret;
  2791. }
  2792.  
  2793. FL_OBJECT *
  2794. fl_create_xyplot(int t, float x, float y, float w, float h,
  2795.          const char *lab)
  2796. {
  2797.     FL_OBJECT *ob;
  2798.     Plot_h *sp;
  2799.     int i;
  2800.  
  2801.     ob = fl_make_object(FL_XYPLOT, t, x, y, w, h, lab, handle_it);
  2802.  
  2803.     ob->boxtype = FL_CHART_BOXTYPE;
  2804.     ob->col1 = FL_CHART_COL1;
  2805.     ob->col2 = FL_CHART_COL1;
  2806.     ob->align = FL_CHART_ALIGN;
  2807.     ob->lcol = FL_CHART_LCOL;
  2808.  
  2809.     ob->active = (t == FL_ACTIVE_XYPLOT);
  2810.  
  2811.     ob->spec = calloc(1, sizeof(Plot_h));
  2812.  
  2813.     /* initialization specific to xyplot stuff */
  2814.  
  2815.     sp = (Plot_h *) ob->spec;
  2816.     sp->x = malloc(1);
  2817.     sp->y = malloc(1);
  2818.     sp->n = -1;
  2819.     sp->always = 0;
  2820.     sp->xmajor = 5;
  2821.     sp->xminor = 5;
  2822.     sp->ymajor = 1;
  2823.     sp->yminor = 2;
  2824.     sp->pcol = sp->lcol = BLACK;/* plot colors */
  2825.     sp->autoybounds = 1;
  2826.     sp->autoxbounds = 1;
  2827.     sp->lsize = FL_SMALL_FONT;
  2828.     sp->lstyle = FL_NORMAL_STYLE;
  2829.     sp->xmin = sp->ymin = 0.0;
  2830.     sp->xmax = sp->ymax = 1.0;
  2831.     sp->within = 0;
  2832.     sp->p_size = P_SIZE;
  2833.     sp->c_size = C_SIZE;
  2834.     sp->intpl = 0;
  2835.  
  2836.     for (i = 0; i < MAXTEXT; i++)
  2837.       {
  2838.       sp->vert[i] = 0;    /* vertical */
  2839.       sp->tcol[i] = sp->lcol;
  2840.       sp->tsize[i] = FL_SMALL_FONT;
  2841.       sp->text[i][0] = '\0';
  2842.       }
  2843.     return ob;
  2844. }
  2845.  
  2846. FL_OBJECT *
  2847. fl_add_xyplot(int type, float x, float y, float w, float h,
  2848.           const char *lab)
  2849. {
  2850.     FL_OBJECT *ob = fl_create_xyplot(type, x, y, w, h, lab);
  2851.     fl_add_object(fl_current_form, ob);
  2852.     return ob;
  2853. }
  2854.  
  2855. void
  2856. fl_clear_xyplot_text(FL_OBJECT * ob)
  2857. {
  2858.     Plot_h *p;
  2859.     int n;
  2860.  
  2861.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  2862.     return;
  2863.  
  2864.     /* need to do this only if in single buffer mode */
  2865.     if (!ob->form->doublebuf && ob->form->visible && ob->visible)
  2866.     draw_xyplot_text(ob, 1);
  2867.  
  2868.     p = (SPEC *) ob->spec;
  2869.     for (n = 0; n < MAXTEXT; n++)
  2870.     p->text[n][0] = '\0';
  2871. }
  2872.  
  2873. /* specific routines */
  2874. void
  2875. fl_clear_xyplot(FL_OBJECT * ob)
  2876. {
  2877.     Plot_h *p;
  2878.  
  2879.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  2880.     return;
  2881.     p = (Plot_h *) ob->spec;
  2882.     if (p->x)
  2883.     p->x = realloc(p->x, 4);
  2884.     if (p->y)
  2885.     p->y = realloc(p->y, 4);
  2886.     p->n = -1;
  2887.     fl_clear_xyplot_text(ob);
  2888. }
  2889.  
  2890. void
  2891. fl_set_xyplot_interpolate(FL_OBJECT * ob, int deg)
  2892. {
  2893.     Plot_h *p;
  2894.  
  2895.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  2896.     return;
  2897.     p = (Plot_h *) ob->spec;
  2898.     p->intpl = deg;
  2899.     fl_redraw_object(ob);
  2900. }
  2901.  
  2902. /* Fill the xyplot stucture */
  2903. static void
  2904. fill_xyplot(FL_OBJECT * ob, float *x, float *y, int n,
  2905.         const char *title, const char *xlab, const char *ylab)
  2906. {
  2907.     Plot_h *p;
  2908.     size_t mem;
  2909.  
  2910.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  2911.     return;
  2912.  
  2913.     if (n <= 0 || !x || !y)
  2914.     return;
  2915.  
  2916.     p = (Plot_h *) ob->spec;
  2917.     mem = sizeof(float) * n;
  2918.  
  2919.     if (!(p->x = p->x ? realloc(p->x, mem) : malloc(mem)) ||
  2920.     !(p->y = p->y ? realloc(p->y, mem) : malloc(mem)))
  2921.       {
  2922.       return;
  2923.       }
  2924.     if (!(memcpy(p->x, x, sizeof(float) * n)) ||
  2925.     ! (memcpy(p->y, y, sizeof(float) * n)))
  2926.       {
  2927.       return;
  2928.       }
  2929.     p->n = n;
  2930.     strncpy(p->title, title ? title : "", MAXTEXTL);
  2931.     strncpy(p->xlabel, xlab ? xlab : "", MAXTEXTL);
  2932.     strncpy(p->ylabel, ylab ? ylab : "", MAXTEXTL);
  2933.     p->title[MAXTEXTL - 1] = '\0';
  2934.     p->xlabel[MAXTEXTL - 1] = '\0';
  2935.     p->ylabel[MAXTEXTL - 1] = '\0';
  2936. }
  2937.  
  2938. /* A hack to change a point for ACTIVE_XYPLOT *****/
  2939. void
  2940. fl_set_xyplot_point(FL_OBJECT * ob, float x, float y, int i)
  2941. {
  2942.     Plot_h *p;
  2943.  
  2944.     if (!ob || ob->objclass != FL_XYPLOT || !(p = (Plot_h *) ob->spec))
  2945.     return;
  2946.  
  2947.  
  2948.     if (ob->visible)
  2949.       {
  2950.       draw_changed_part(ob, i, x, y);
  2951.       }
  2952.     else
  2953.       {
  2954.       fl_redraw_object(ob);
  2955.       }
  2956.  
  2957.     if (i >= 0 && i < p->n)
  2958.       {
  2959.       p->x[i] = x;
  2960.       p->y[i] = y;
  2961.       }
  2962. }
  2963.  
  2964. /*******************************************************************
  2965.  * This routine draws the XYPLOT only, NOT labels, titles etc.
  2966.  ******************************************************************/
  2967. void
  2968. fl_set_xyplot_only(FL_OBJECT * ob, float *x, float *y, int n,
  2969.            const char *title, const char *xlab, const char *ylab)
  2970. {
  2971.     int m;
  2972.     Plot_h *p;
  2973.  
  2974.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  2975.     return;
  2976.     if (n <= 0 || !x || !y)
  2977.     return;
  2978.  
  2979.     fill_xyplot(ob, x, y, n, title, xlab, ylab);
  2980.     p = (Plot_h *) ob->spec;
  2981.  
  2982.     if (ob->form->doublebuf)
  2983.       {
  2984.       fl_redraw_object(ob);
  2985.       }
  2986.     else if (ob->form->window > 0)
  2987.       {
  2988.       /* for less flickering if continously changing */
  2989.       m = C_SIZE / 2 + 1;
  2990.       set_current_window(ob->form->window);
  2991.       fl_color(ob->col1);
  2992.       rectf(p->xi - m, p->yi - m, p->xf + m, p->yf + m);
  2993.       doit(ob->type, ob);
  2994.       do_xyplot_tics(p);
  2995.       }
  2996. }
  2997.  
  2998. /***************************************************************
  2999.  * This routine does it all
  3000.  *************************************************************/
  3001. void
  3002. fl_set_xyplot(FL_OBJECT * ob, float *x, float *y, int n,
  3003.           const char *title, const char *xlab, const char *ylab)
  3004. {
  3005.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3006.     return;
  3007.     if (n <= 0 || !x || !y)
  3008.     return;
  3009.     fill_xyplot(ob, x, y, n, title, xlab, ylab);
  3010.     fl_redraw_object(ob);
  3011. }
  3012.  
  3013. /* Specifying a negative value will leave the old setting alone */
  3014. void
  3015. fl_set_xyplot_autobounds(FL_OBJECT * ob, int xb, int yb)
  3016. {
  3017.     Plot_h *p;
  3018.  
  3019.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3020.     return;
  3021.     p = (Plot_h *) ob->spec;
  3022.     if (xb >= 0)
  3023.     p->autoxbounds = xb;
  3024.     if (yb >= 0)
  3025.     p->autoybounds = yb;
  3026.     get_xyplot_bounds(p);
  3027. }
  3028.  
  3029. void
  3030. fl_get_xyplot(FL_OBJECT * ob, float *x, float *y, int *n)
  3031. {
  3032.     Plot_h *p;
  3033.  
  3034.     if (ob == 0 || ob->objclass != FL_XYPLOT || !x || !y)
  3035.     return;
  3036.     p = (Plot_h *) ob->spec;
  3037.  
  3038.     if (p->n <= 0)
  3039.     return;
  3040.     *n = p->n;
  3041.  
  3042.     if (memcpy(x, p->x, sizeof(float) * p->n) == 0 ||
  3043.     memcpy(y, p->y, sizeof(float) * p->n) == 0)
  3044.       {
  3045.       return;
  3046.       }
  3047. }
  3048.  
  3049. void
  3050. fl_set_xyplot_return(FL_OBJECT * ob, int y)
  3051. {
  3052.     Plot_h *p;
  3053.  
  3054.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3055.     return;
  3056.     if (!ob->active)
  3057.     return;
  3058.     p = (Plot_h *) ob->spec;
  3059.     p->always = y;
  3060. }
  3061.  
  3062. void
  3063. fl_get_active_xyplot(FL_OBJECT * ob, float *x, float *y, int *i)
  3064. {
  3065.     Plot_h *p;
  3066.     int l;
  3067.  
  3068.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3069.     return;
  3070.     p = (Plot_h *) ob->spec;
  3071.     if (!p->within)
  3072.     return;
  3073.  
  3074.     l = *i = Abs(p->within) - 1;
  3075.     *x = p->x[l];
  3076.     *y = p->y[l];
  3077. }
  3078.  
  3079. void
  3080. fl_set_xyplot_xbounds(FL_OBJECT * ob, float xmin, float xmax)
  3081. {
  3082.     Plot_h *p;
  3083.     if (ob == 0 || ob->objclass != FL_XYPLOT || xmin >= xmax)
  3084.     return;
  3085.     p = (Plot_h *) ob->spec;
  3086.     p->xmin = xmin;
  3087.     p->xmax = xmax;
  3088.     p->autoxbounds = 0;
  3089.     fl_redraw_object(ob);
  3090. }
  3091.  
  3092. void
  3093. fl_set_xyplot_ybounds(FL_OBJECT * ob, float ymin, float ymax)
  3094. {
  3095.     Plot_h *p;
  3096.     if (ob == 0 || ob->objclass != FL_XYPLOT || ymin >= ymax)
  3097.     return;
  3098.     p = (Plot_h *) ob->spec;
  3099.     p->ymin = ymin;
  3100.     p->ymax = ymax;
  3101.     p->autoybounds = 0;
  3102.     fl_redraw_object(ob);
  3103. }
  3104.  
  3105. void
  3106. fl_set_xyplot_lsize(FL_OBJECT * ob, float size)
  3107. {
  3108.     Plot_h *p;
  3109.  
  3110.     if (ob == 0 || ob->objclass != FL_XYPLOT || size < 0.0 || size > 80.0)
  3111.     return;
  3112.  
  3113.     p = (Plot_h *) ob->spec;
  3114.     p->lsize = size;
  3115.     fl_redraw_object(ob);
  3116. }
  3117.  
  3118. void
  3119. fl_set_xyplot_legend(FL_OBJECT * ob, int size)
  3120. {
  3121.     Plot_h *p;
  3122.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3123.     return;
  3124.     p = (Plot_h *) ob->spec;
  3125.  
  3126.     p->p_size = p->c_size = size;
  3127. }
  3128.  
  3129. void
  3130. fl_set_xyplot_colors(FL_OBJECT * ob, int pc, int lc)
  3131. {
  3132.     Plot_h *p;
  3133.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3134.     return;
  3135.     p = (Plot_h *) ob->spec;
  3136.     if (pc >= 0)
  3137.     p->pcol = pc;
  3138.     if (lc >= 0)
  3139.     p->lcol = lc;
  3140.     fl_redraw_object(ob);
  3141. }
  3142.  
  3143. void
  3144. fl_set_xyplot_xscale(FL_OBJECT * ob, int major, int minor)
  3145. {
  3146.     Plot_h *p;
  3147.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3148.     return;
  3149.     p = (Plot_h *) ob->spec;
  3150.  
  3151.     p->xmajor = major;
  3152.     p->xminor = minor;
  3153.     fl_redraw_object(ob);
  3154. }
  3155.  
  3156. void
  3157. fl_set_xyplot_yscale(FL_OBJECT * ob, int major, int minor)
  3158. {
  3159.     Plot_h *p;
  3160.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3161.     return;
  3162.     p = (Plot_h *) ob->spec;
  3163.  
  3164.     p->ymajor = major;
  3165.     p->yminor = minor;
  3166.     fl_redraw_object(ob);
  3167. }
  3168.  
  3169. /********************************************************************
  3170.  * Add arbitary text, but don't draw it (yet)
  3171.  *******************************************************************/
  3172. void
  3173. fl_add_xyplot_text(FL_OBJECT * ob, float x, float y, int i,
  3174.          const char *text, int vert, int col, float size, int style)
  3175. {
  3176.     Plot_h *p;
  3177.  
  3178.     if (ob == 0 || ob->objclass != FL_XYPLOT || i >= MAXTEXT)
  3179.     return;
  3180.  
  3181.     if (!ob->form->doublebuf && ob->form->visible && ob->visible)
  3182.     draw_xyplot_text(ob, 1);
  3183.  
  3184.     p = (Plot_h *) ob->spec;
  3185.     p->tx[i] = x;
  3186.     p->ty[i] = y;
  3187.  
  3188.     if (col >= 0)
  3189.     p->tcol[i] = col;
  3190.     if (size > 0.0)
  3191.     p->tsize[i] = size;
  3192.  
  3193.     p->vert[i] = vert;
  3194.     p->tstyle[i] = style;
  3195.     if (!text)
  3196.     p->text[i][0] = '\0';
  3197.     else
  3198.       {
  3199.       strncpy(p->text[i], text, MAXTEXTL);
  3200.       p->text[i][MAXTEXTL - 1] = '\0';
  3201.       }
  3202.  
  3203.     if (!ob->form->doublebuf && ob->form->visible && ob->visible)
  3204.     draw_xyplot_text(ob, 0);
  3205.     else
  3206.     fl_redraw_object(ob);
  3207. }
  3208.  
  3209. /*************************************************************
  3210.  * Add the text and drawit
  3211.  ************************************************************/
  3212. void
  3213. fl_set_xyplot_text(FL_OBJECT * ob, float x, float y, int i,
  3214.          const char *text, int vert, int col, float size, int style)
  3215. {
  3216.     if (ob == 0 || ob->objclass != FL_XYPLOT || i >= MAXTEXT)
  3217.     return;
  3218.  
  3219.     fl_add_xyplot_text(ob, x, y, i, text, vert, col, size, style);
  3220.  
  3221.     fl_redraw_object(ob);
  3222. }
  3223.  
  3224. void
  3225. fl_set_xyplot_type(FL_OBJECT * ob, int type)
  3226. {
  3227.     if (ob == 0 || ob->objclass != FL_XYPLOT)
  3228.     return;
  3229.     if (type < 0 || type >= FL_XYPLOT_MAXTYPE)
  3230.     type = 0;
  3231.     ob->type = type;
  3232.     fl_redraw_object(ob);
  3233. }
  3234.  
  3235.  
  3236. #include <math.h>
  3237. #define ADVANCE 0.2        /* shoulde not be greater than 0.25 */
  3238. #define FACTOR  1.8        /* max major expansion              */
  3239. static float trunc_f(float, int);
  3240. static float
  3241. gen_tic(float tmin, float tmax, int major, int minor)
  3242. {
  3243.     float r_range, l_range, n_range;
  3244.     float tic;
  3245.     int ipow, digit;
  3246.  
  3247.     /* handle special case: Min, MAX and one tic */
  3248.     if (major == 1 && minor == 2)
  3249.       {
  3250.       tic = (tmax - tmin) * 0.5 * 0.999;
  3251.       return tic;
  3252.       }
  3253.     r_range = tmax - tmin;
  3254.     l_range = (float) log10(r_range);
  3255.     ipow = (int) ((l_range > 0.0) ? (int) l_range : (int) l_range - 1);
  3256.     /* normalized range is between 0 and 10 */
  3257.     n_range = (float) pow(10.0, (l_range - ipow));
  3258.     n_range += ADVANCE;
  3259.  
  3260.     tic = n_range / major;
  3261.     digit = (tic < 1.0);
  3262.     tic = trunc_f(tic, digit);
  3263.     tic /= (float) minor;
  3264.     tic = trunc_f(tic, 1);
  3265.     tic *= pow(10.0, (double) ipow);
  3266.  
  3267.     /* Final check */
  3268.     n_range = (r_range / (tic * minor * major));
  3269.     if (n_range > FACTOR)
  3270.       {
  3271.       ipow = (n_range / FACTOR);
  3272.       if (ipow >= 1)
  3273.           tic *= 2.0 * ipow;
  3274.       else
  3275.           tic *= 2.0 * n_range / FACTOR;
  3276.       tic = trunc_f(tic, 1);
  3277.       }
  3278.     return tic;
  3279. }
  3280.  
  3281. /*
  3282.  * truncate a floating point number to requested significant digits
  3283.  */
  3284. static float
  3285. trunc_f(float f, int digit)
  3286. {
  3287.     int ipow, itmp, c;
  3288.     float expon, tmp;
  3289.  
  3290.     if (fabs(f) < 1.e-8)
  3291.     return 0.0;
  3292.     if (digit < 0)
  3293.     digit = 1;
  3294.  
  3295.     if (!digit)
  3296.       {
  3297.       if (f > 0.5)
  3298.           return 1.0;
  3299.       else if (f < 0.5)
  3300.           return 0.0;
  3301.       else
  3302.         {
  3303.         itmp = f;
  3304.         return (float) itmp;
  3305.         }
  3306.       }
  3307.     c = digit - 1;
  3308.     expon = log10(f);
  3309.     ipow = (expon > 0.0) ? (int) expon : (int) expon - 1;
  3310.  
  3311.     tmp = pow(10.0, expon - (double) ipow);
  3312.     tmp += ADVANCE;
  3313.     tmp *= pow(10.0, (double) c);
  3314.     itmp = tmp;
  3315.     tmp = (float) itmp;
  3316.     tmp *= pow(10.0, (double) (ipow - c));
  3317.     return tmp;
  3318. }
  3319.  
  3320. /***********************************************************
  3321.  * Forms that show 4 xyplots for histograms
  3322.  **********************************************************/
  3323. static FL_FORM *chart4;
  3324. static FL_OBJECT *chartdone, *ch[4], *txt[4];
  3325.  
  3326. static void create_form_chart4(void);
  3327. static char *ylab[4], *xlab[4], *title[4];
  3328.  
  3329. static float ch4ymin[4] =
  3330. {
  3331.     0, 0, 0, 0
  3332. };
  3333.  
  3334. static float ch4ymax[4] =
  3335. {
  3336.     -1, -1, -1, -1
  3337. };
  3338.  
  3339. static int lstyle = FL_LINEFILL_XYPLOT;
  3340.  
  3341. /*ARGSUSED*/
  3342. static void
  3343. change_chart4_style(FL_OBJECT * s, long p)
  3344. {
  3345.     int i;
  3346.  
  3347.     create_form_chart4();
  3348.     fl_freeze_form(chart4);
  3349.     lstyle++;
  3350.     lstyle %= FL_XYPLOT_MAXTYPE;
  3351.     for (i = 0; i < 4; i++)
  3352.     fl_set_xyplot_type(ch[i], lstyle);
  3353.     fl_unfreeze_form(chart4);
  3354. }
  3355. /* ARGSUSED */
  3356. static void
  3357. hide_chart4(FL_OBJECT * ob, long q)
  3358. {
  3359.     static long hmenu = -1;
  3360.     static int xmin = 0, xmax = 255;
  3361.     static int ymin = 0, ymax = 100;
  3362.     int i;
  3363.  
  3364.     if (hmenu < 0)
  3365.     hmenu = defpup("Histogram%t|XScale|Yscale|Reset|Style|Done %x100");
  3366.  
  3367.     switch (dopup(hmenu))
  3368.       {
  3369.       case 100:
  3370.       bit_hide_form(chart4);
  3371.       fl_clear_xyplot(ch[0]);
  3372.       fl_clear_xyplot(ch[1]);
  3373.       fl_clear_xyplot(ch[2]);
  3374.       fl_clear_xyplot(ch[3]);
  3375.       break;
  3376.       case 1:
  3377.       get2int("Min Pixel Value", &xmin, 0, 255,
  3378.           "Max Pixel Value", &xmax, 0, 255,
  3379.           0, 0, -1, 0);
  3380.       fl_freeze_form(chart4);
  3381.       for (i = 0; i < 4; i++)
  3382.           fl_set_xyplot_xbounds(ch[i], xmin, xmax);
  3383.       fl_unfreeze_form(chart4);
  3384.       break;
  3385.       case 2:
  3386.       get2int("Min Percentage", &ymin, 0, 100,
  3387.           "Max Percentage", &ymax, 0, 100, 0, 0, -1, 0);
  3388.       fl_freeze_form(chart4);
  3389.       for (i = 0; i < 4; i++)
  3390.           fl_set_xyplot_ybounds(ch[i], ymin * 0.01, ymax * 0.01);
  3391.       fl_unfreeze_form(chart4);
  3392.       break;
  3393.       case 3:
  3394.       /*
  3395.        * need to force a redraw (via unfreeze) because set_auto does not
  3396.        * draw the object automatically
  3397.        */
  3398.       fl_freeze_form(chart4);
  3399.       for (i = 0; i < 4; i++)
  3400.           fl_set_xyplot_autobounds(ch[i], 1, 1);
  3401.       fl_unfreeze_form(chart4);
  3402.       break;
  3403.       case 4:
  3404.       change_chart4_style(0, 0);
  3405.       break;
  3406.       }
  3407. }
  3408.  
  3409. void
  3410. set_chart4_ybounds(float *ymin, float *ymax)
  3411. {
  3412.     int i;
  3413.     for (i = 0; i < 4; i++)
  3414.       {
  3415.       ch4ymin[i] = ymin[i];
  3416.       ch4ymax[i] = ymax[i];
  3417.       }
  3418. }
  3419.  
  3420. void
  3421. set_chart4_text(const char *l1, const char *l2, const char *l3, const char *l4)
  3422. {
  3423.     create_form_chart4();
  3424.     fl_freeze_form(chart4);
  3425.     fl_set_object_label(txt[0], l1);
  3426.     fl_set_object_label(txt[1], l2);
  3427.     fl_set_object_label(txt[2], l3);
  3428.     fl_set_object_label(txt[3], l4);
  3429.     fl_unfreeze_form(chart4);
  3430. }
  3431.  
  3432. void
  3433. set_chart4_style(long p)
  3434. {
  3435.     lstyle = p;
  3436.     create_form_chart4();
  3437.     fl_set_xyplot_type(ch[0], p);
  3438.     fl_set_xyplot_type(ch[1], p);
  3439.     fl_set_xyplot_type(ch[2], p);
  3440.     fl_set_xyplot_type(ch[3], p);
  3441. }
  3442.  
  3443. void
  3444. show_chart4(const char *ctitle, float *x, float *y[], int n)
  3445. {
  3446.     int i;
  3447.  
  3448.     create_form_chart4();
  3449.     minsize(300, 300);
  3450.     fl_freeze_form(chart4);
  3451.     fl_set_object_label(chartdone, ctitle);
  3452.     for (i = 0; i < 4; i++)
  3453.       {
  3454.       fl_set_xyplot(ch[i], x, y[i], n, title[i], xlab[i], ylab[i]);
  3455.       if (ch4ymin[i] < ch4ymax[i])
  3456.           fl_set_xyplot_ybounds(ch[i], ch4ymin[i], ch4ymax[i]);
  3457.       ch4ymin[i] = 0.0;
  3458.       ch4ymax[i] = -1.0;
  3459.       }
  3460.     fl_unfreeze_form(chart4);
  3461.     bit_show_form(chart4, FL_PLACE_FREE, 1, ctitle);
  3462. }
  3463.  
  3464.  
  3465. static FL_OBJECT *hhh;
  3466. void
  3467. set_chart4_help(int h)
  3468. {
  3469.     create_form_chart4();
  3470.     fl_set_call_back(hhh, help_cb, h);
  3471. }
  3472.  
  3473. static void
  3474. create_form_chart4(void)
  3475. {
  3476.     FL_OBJECT *obj;
  3477.  
  3478.     if (chart4)
  3479.     return;
  3480.  
  3481.     chart4 = fl_bgn_form(FL_NO_BOX, 445.0, 515.0);
  3482.     obj = fl_add_box(FL_FLAT_BOX, 0.0, 0.0, 445.0, 515.0, "");
  3483.     hhh = fl_add_button(FL_HB, 0.0, 0.0, 445, 515, "");
  3484.     ch[0] = fl_add_xyplot(lstyle, 10.0, 10.0, 420.0, 110.0, "");
  3485.     fl_set_xyplot_colors(ch[0], FL_RED, FL_BLACK);
  3486.     ch[1] = fl_add_xyplot(lstyle, 10.0, 125.0, 420.0, 110.0, "");
  3487.     fl_set_xyplot_colors(ch[1], FL_GREEN, FL_BLACK);
  3488.     ch[2] = fl_add_xyplot(lstyle, 10.0, 240.0, 420.0, 110.0, "");
  3489.     fl_set_xyplot_colors(ch[2], FL_BLUE, FL_BLACK);
  3490.     ch[3] = fl_add_xyplot(lstyle, 10.0, 355.0, 420.0, 110.0, "");
  3491.     fl_set_xyplot_colors(ch[3], FL_WHITE, FL_BLACK);
  3492.  
  3493.     chartdone = obj = fl_add_button(FL_NB, 120.0, 475.0, 215.0, 31.0, "");
  3494.     fl_set_object_boxtype(obj, FL_RSHADOW_BOX);
  3495.     fl_set_object_color(obj, FL_MAGIC1, FL_RED);
  3496.     fl_set_object_lcol(obj, 4);
  3497.     fl_set_object_lstyle(obj, FL_ENGRAVED_STYLE);
  3498.     fl_set_call_back(obj, hide_chart4, 0);
  3499.     txt[0] = obj = fl_add_text(FL_NT, 240.0, 85.0, 150.0, 20.0, "");
  3500.     fl_set_object_lsize(txt[0], FL_SMALL_FONT);
  3501.     txt[1] = obj = fl_add_text(FL_NT, 240.0, 200.0, 150.0, 20.0, "");
  3502.     fl_set_object_lsize(txt[1], FL_SMALL_FONT);
  3503.     txt[2] = obj = fl_add_text(FL_NT, 240.0, 315.0, 150.0, 20.0, "");
  3504.     fl_set_object_lsize(txt[2], FL_SMALL_FONT);
  3505.     txt[3] = obj = fl_add_text(FL_NT, 240.0, 433.0, 150.0, 20.0, "");
  3506.     fl_set_object_lsize(txt[3], FL_SMALL_FONT);
  3507.     fl_end_form();
  3508. }
  3509.  
  3510. /*******************************************************************
  3511.  * Get an angle. in tenth of a degree
  3512.  ******************************************************************/
  3513. static FL_FORM *dirform;
  3514. static FL_OBJECT *cdir, *dircancel, *dirok, *dirtitle;
  3515. static void create_form_dir(void);
  3516. static float dirval;
  3517.  
  3518. /* cancel returns -1, else 0 or positive */
  3519. /* also the val should be in tenth of a degree */
  3520. int
  3521. get_orientation(const char *dirprompt, int *val, int im)
  3522. {
  3523.     int def = *val, done;
  3524.     short garb;
  3525.     FL_OBJECT *ret;
  3526.  
  3527.     create_form_dir();
  3528.     fl_set_object_label(dirtitle, dirprompt);
  3529.     fl_set_object_label(cdir, ftoa(def * 0.1, 1));
  3530.     bit_show_form(dirform, FL_PLACE_MOUSE, 0, dirprompt);
  3531.  
  3532.     do
  3533.       {
  3534.       done = ((ret = fl_do_forms()) == dircancel || ret == dirok);
  3535.       if (ret == FL_EVENT)
  3536.           (void) bit_qread(&garb);
  3537.       }
  3538.     while (!done && !im);
  3539.  
  3540.     *val = (((ret != dircancel) ? dirval : def) * 10.0);
  3541.     if (done)
  3542.     bit_hide_form(dirform);
  3543.  
  3544.     return ret == dircancel ? -1 : done;
  3545. }
  3546.  
  3547. /*************************************************************/
  3548.  
  3549. #define MAXSTEP 5.0
  3550. #define MINSTEP 0.5
  3551.  
  3552. /* ARGSUSED */
  3553. static void
  3554. dir_shortcuts(FL_OBJECT * ob, long q)
  3555. {
  3556.     static int vals[] =
  3557.     {
  3558.     225, -90, -45, 180, 0, 0, 125, 90, 45
  3559.     };
  3560.  
  3561.     dirval = vals[q];
  3562.     fl_set_object_label(cdir, ftoa(dirval, 1));
  3563.     fl_qenter(SPACEKEY, 0);
  3564. }
  3565.  
  3566. /* ARGSUSED */
  3567. static void
  3568. change_it(FL_OBJECT * ob, long q)
  3569. {
  3570.     if (q == 4)
  3571.     dirval -= MINSTEP;
  3572.     else if (q == 44)
  3573.     dirval -= MAXSTEP;
  3574.     else if (q == 66)
  3575.     dirval += MAXSTEP;
  3576.     else if (q == 6)
  3577.     dirval += MINSTEP;
  3578.  
  3579.     if (dirval > 360)
  3580.     dirval -= 360.0;
  3581.     if (dirval < -360)
  3582.     dirval += 360.0;
  3583.     fl_set_object_label(cdir, ftoa(dirval, 1));
  3584.     fl_qenter(SPACEKEY, 1);
  3585. }
  3586.  
  3587. static void
  3588. create_form_dir(void)
  3589. {
  3590.     FL_OBJECT *obj;
  3591.     static const char *lab[] =
  3592.     {
  3593.     "@1", "@2", "@3", "@4", "@circle", "@6", "@7", "@8", "@9"
  3594.     };
  3595.  
  3596.     int i, j, k;
  3597.     float x, y, dx, dy;
  3598.  
  3599.     if (dirform)
  3600.     return;
  3601.  
  3602.     dirform = fl_bgn_form(FL_NO_BOX, 170.0, 190.0);
  3603.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 170.0, 190.0, "");
  3604.     dirtitle = obj = fl_add_text(FL_NO_BOX, 10, 165, 150, 15, "");
  3605.     fl_set_object_lcol(obj, FL_BLUE);
  3606.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  3607.     fl_set_object_lstyle(obj, FL_BOLD_STYLE);
  3608.  
  3609.     fl_bgn_group();
  3610.  
  3611.     dx = dy = 30.0;
  3612.     x = 40;
  3613.  
  3614.     for (j = 0, k = 0, y = 70.0; j < 3; j++, y += dy, x = 40)
  3615.       {
  3616.       for (x = 40, i = 0; i < 3; i++, x += dx, k++)
  3617.         {
  3618.         obj = fl_add_button(FL_NB, x, y, dx, dy, lab[k]);
  3619.         fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3620.         fl_set_object_color(obj, 47, 4);
  3621.         fl_set_object_lcol(obj, 1);
  3622.         fl_set_call_back(obj, dir_shortcuts, k);
  3623.         }
  3624.       }
  3625.     fl_end_group();
  3626.  
  3627.     obj = fl_add_button(FL_TB, 10.0, 40.0, 25.0, 25.0, "@<<");
  3628.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3629.     fl_set_object_color(obj, 47, 4);
  3630.     fl_set_object_lcol(obj, 4);
  3631.     fl_set_call_back(obj, change_it, 44);
  3632.     obj = fl_add_button(FL_TB, 35.0, 40.0, 25.0, 25.0, "@<");
  3633.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3634.     fl_set_object_color(obj, 47, 4);
  3635.     fl_set_call_back(obj, change_it, 4);
  3636.     fl_set_object_lcol(obj, 4);
  3637.     obj = fl_add_button(FL_TB, 135.0, 40.0, 25.0, 25.0, "@>>");
  3638.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3639.     fl_set_object_color(obj, 47, 4);
  3640.     fl_set_object_lcol(obj, 4);
  3641.     fl_set_call_back(obj, change_it, 66);
  3642.     obj = fl_add_button(FL_TB, 110.0, 40.0, 25.0, 25.0, "@>");
  3643.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3644.     fl_set_object_color(obj, 47, 4);
  3645.     fl_set_object_lcol(obj, 4);
  3646.     fl_set_call_back(obj, change_it, 6);
  3647.     cdir = obj = fl_add_text(FL_NT, 60.0, 40.0, 50.0, 25.0, "");
  3648.     fl_set_object_boxtype(obj, FL_FRAME_BOX);
  3649.     fl_set_object_lcol(obj, 4);
  3650.     fl_set_object_lsize(obj, 10.0);
  3651.     fl_set_object_align(obj, FL_ALIGN_CENTER);
  3652.     dirok = obj = fl_add_button(FL_NB, 100.0, 10.0, 60.0, 25.0, "Done");
  3653.     fl_set_object_lsize(obj, 10.0);
  3654.     fl_end_form();
  3655. }
  3656.  
  3657. /****************************************************************
  3658.  * FORM class RGB_ICON.
  3659.  *  A hack. Not up to the form standard
  3660.  ***************************************************************{*/
  3661.  
  3662. #include "bit.h"
  3663. #include "extern.h"
  3664. #include "dmalloc.h"
  3665.  
  3666. typedef struct
  3667. {
  3668.     int val;            /* if pressed                    */
  3669.     int dblclk;            /* if double clicked             */
  3670.     rgba_t **rgba;        /* the raster                    */
  3671.     int external;        /* if rgba is alloced elsewhere  */
  3672.     int w, h;            /* dimension of the icon         */
  3673.     char *filename;        /* the filenae for this icon     */
  3674.     char *info;            /* other info about this icon    */
  3675. }
  3676. ICON_SPEC;
  3677.  
  3678. static void
  3679. free_icon_image(ICON_SPEC * sp)
  3680. {
  3681.     if (!sp->external)
  3682.     free_mat(sp->rgba);
  3683.     sp->rgba = 0;
  3684.     sp->external = 0;
  3685. }
  3686.  
  3687. static void
  3688. free_rgb_icon(ICON_SPEC * sp)
  3689. {
  3690.     free_icon_image(sp);
  3691.     if (sp->filename)
  3692.     free(sp->filename);
  3693.     if (sp->info)
  3694.     free(sp->info);
  3695.     sp->info = sp->filename = 0;
  3696. }
  3697.  
  3698. /***********************************************************
  3699.  * Check if an icon is pushed
  3700.  ***********************************************************/
  3701. int
  3702. fl_get_icon(FL_OBJECT * ob)
  3703. {
  3704.     return ((ICON_SPEC *) (ob->spec))->val;
  3705. }
  3706.  
  3707. /************************************************************
  3708.  * push it from within program
  3709.  ***********************************************************/
  3710. void
  3711. fl_set_icon(FL_OBJECT * ob, int pushed)
  3712. {
  3713.     ((ICON_SPEC *) (ob->spec))->val = pushed;
  3714.     if (ob->type == FL_RADIO_ICON)
  3715.     ob->pushed = pushed;
  3716.     fl_redraw_object(ob);
  3717. }
  3718.  
  3719. /***********************************************************
  3720.  * Check if an icon is double clicked on
  3721.  **********************************************************/
  3722. int
  3723. fl_get_icon_dblclk(FL_OBJECT * ob)
  3724. {
  3725.     return ((ICON_SPEC *) (ob->spec))->dblclk;
  3726. }
  3727.  
  3728. #include <math.h>
  3729.  
  3730. static void
  3731. draw_image(FL_OBJECT * ob, ICON_SPEC * sp, int *x, int *y)
  3732. {
  3733.     int w, h, xx, yy;
  3734.     unsigned long *ras;
  3735.     /* if no image, generate a default */
  3736.     if (!sp->rgba)
  3737.       {
  3738.       cpack(0x000000ff);
  3739.       w = sp->w = ob->w - 10;
  3740.       h = sp->h = ob->h - 10;
  3741.       gl_plus(ob->x + ob->w / 2, ob->y + ob->h / 2, w / 2, h / 2, 0, 450);
  3742.  
  3743.       xx = ob->x + (ob->w - w) / 2;
  3744.       yy = ob->y + (ob->h - h) / 2;
  3745.       }
  3746.     else
  3747.       {
  3748.       ras = sp->rgba[0];
  3749.       w = sp->w;
  3750.       h = sp->h;
  3751.       xx = ob->x + (ob->w - w) / 2;
  3752.       yy = ob->y + (ob->h - h) / 2;
  3753.       lrectwrite(xx, yy, xx + w - 1, yy + h - 1, ras);
  3754.       }
  3755.     *x = xx;
  3756.     *y = yy;
  3757. }
  3758.  
  3759.  
  3760. static void
  3761. draw_icon(FL_OBJECT * ob)
  3762. {
  3763.     ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
  3764.     int x, y;
  3765.     long owin = winget();
  3766.  
  3767.     set_current_window(ob->form->window);
  3768.  
  3769.     if (sp->val && ob->boxtype == FL_UP_BOX)
  3770.     fl_drw_box(FL_DOWN_BOX, ob->x, ob->y, ob->w, ob->h, ob->col1, 2);
  3771.     else
  3772.     fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col1, 2);
  3773.  
  3774.     draw_image(ob, sp, &x, &y);
  3775.  
  3776.     fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  3777.                ob->lcol, ob->lsize, ob->lstyle, ob->label);
  3778.  
  3779.     if (ob->belowmouse || sp->val)
  3780.       {
  3781.       cpack(sp->val ? 0x00ffff00 : 0x0000ffff);
  3782.       recti(x, y, x + sp->w - 1, y + sp->h - 1);
  3783.       if (sp->val)
  3784.           fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  3785.                  FL_RED, ob->lsize, ob->lstyle, ob->label);
  3786.       }
  3787.  
  3788.     set_current_window(owin);
  3789. }
  3790.  
  3791. /*******************************************************************
  3792.  * Handle mouse events for icons
  3793.  *
  3794.  *  Double click is considered true if two clicks are seperated
  3795.  *  by less than DSEP (in milli-seconds)
  3796.  ******************************************************************/
  3797.  
  3798. #define DSEP  250
  3799.  
  3800. /*ARGSUSED*/
  3801. static int
  3802. handle_icon(FL_OBJECT * ob, int event, float mx, float my, char k)
  3803. {
  3804.     int ret = 0;
  3805.     ICON_SPEC *sp = ((ICON_SPEC *) ob->spec);
  3806.     static int oldval;
  3807.     int newval;
  3808.  
  3809.     switch (event)
  3810.       {
  3811.       case FL_DRAW:
  3812.       draw_icon(ob);
  3813.       return 0;
  3814.       case FL_ENTER:
  3815.       case FL_LEAVE:
  3816.       fl_redraw_object(ob);
  3817.       return 0;
  3818.       case FL_PUSH:
  3819.       oldval = sp->val;
  3820.       sp->val = !sp->val;
  3821.       sp->dblclk = 0;
  3822.       fl_redraw_object(ob);
  3823.       return (ob->type == FL_TOUCH_ICON);
  3824.       case FL_RELEASE:
  3825.       if (ob->type == FL_RADIO_ICON)
  3826.           return 1;
  3827.       else if (ob->type == FL_PUSH_ICON)
  3828.           return (sp->val != oldval);
  3829.       else if (ob->type == FL_DBL_CLK_ICON)
  3830.         {
  3831.         sp->dblclk = (time_passed() < DSEP);
  3832.         reset_time();
  3833.         return (sp->dblclk || (sp->val != oldval));
  3834.         }
  3835.       else if (sp->val == 0)
  3836.           return 0;
  3837.       sp->val = 0;
  3838.       fl_redraw_object(ob);
  3839.       return (ob->type != FL_TOUCH_ICON);
  3840.  
  3841.       case FL_MOUSE:
  3842.       if (ob->type != FL_RADIO_ICON)
  3843.         {
  3844.         if (mx < ob->x || mx > (ob->x + ob->w) ||
  3845.             my < ob->y || my > (ob->y + ob->h))
  3846.           {
  3847.               newval = oldval;
  3848.           }
  3849.         else
  3850.           {
  3851.               newval = !oldval;
  3852.           }
  3853.         if (sp->val != newval)
  3854.           {
  3855.               sp->val = newval;
  3856.               fl_redraw_object(ob);
  3857.           }
  3858.         }
  3859.       return (sp->val && ob->type == FL_TOUCH_ICON);
  3860.  
  3861.       case FL_FREEMEM:
  3862.       free_rgb_icon(sp);
  3863.       break;
  3864.       }
  3865.     return ret;
  3866. }
  3867.  
  3868.  
  3869. static FL_OBJECT *
  3870. fl_create_icon(int t, float x, float y, float w, float h,
  3871.            const char *lab)
  3872. {
  3873.     FL_OBJECT *ob;
  3874.     ICON_SPEC *sp;
  3875.  
  3876.     ob = fl_make_object(FL_RGB_ICON, t, x, y, w, h, lab, handle_icon);
  3877.  
  3878.     ob->boxtype = FL_ICON_BOXTYPE;
  3879.     ob->col1 = FL_MAGIC1;
  3880.     ob->col2 = FL_MAGIC2;
  3881.     ob->spec = calloc(1, sizeof(ICON_SPEC));
  3882.     ob->radio = (t == FL_RADIO_ICON);
  3883.     ob->lcol = FL_ICON_LCOL;
  3884.     ob->align = FL_ICON_ALIGN;
  3885.     ob->lsize = FL_ICON_LSIZE;
  3886.     ob->lstyle = FL_ICON_LSTYLE;
  3887.  
  3888.     /* initialization specific to rgb images */
  3889.     sp = (ICON_SPEC *) ob->spec;
  3890.     sp->rgba = 0;
  3891.     sp->filename = sp->info = 0;
  3892.     sp->external = 0;
  3893.     return ob;
  3894. }
  3895.  
  3896. FL_OBJECT *
  3897. fl_add_icon(int type, float x, float y, float w, float h,
  3898.         const char *lab)
  3899. {
  3900.     FL_OBJECT *ob = fl_create_icon(type, x, y, w, h, lab);
  3901.     fl_add_object(fl_current_form, ob);
  3902.     return ob;
  3903. }
  3904.  
  3905. FL_OBJECT *
  3906. fl_set_icon_bitmap(FL_OBJECT * ob, int w, int h, rgba_t **ras, int ext)
  3907. {
  3908.     ICON_SPEC *sp = ((ICON_SPEC *) ob->spec);
  3909.  
  3910.     free_icon_image(sp);
  3911.  
  3912.     sp->w = w;
  3913.     sp->h = h;
  3914.     sp->external = ext;
  3915.     sp->rgba = ras;
  3916.  
  3917.     /* if not external, need to copy it */
  3918.     if (!ext)
  3919.       {
  3920.       sp->rgba = get_mat(h, w, sizeof(long));
  3921.       if (ras)
  3922.           memcpy(sp->rgba[0], ras[0], sizeof(unsigned long) * w * h);
  3923.       }
  3924.     return ob;
  3925. }
  3926.  
  3927. static rgba_t **
  3928. load_icon(const char *fname, int *w, int *h)
  3929. {
  3930.     IPTR tmp;
  3931.     int oreport = report_level;
  3932.     rgba_t **pp = 0;
  3933.  
  3934.     report_level = -1;
  3935.     if ((tmp = load_image(fname)))
  3936.       {
  3937.       *w = tmp->w;
  3938.       *h = tmp->h;
  3939.       pp = tmp->mraster;
  3940.       tmp->mraster = 0;
  3941.       }
  3942.     free_image(tmp);
  3943.     report_level = oreport;
  3944.     return pp;
  3945. }
  3946.  
  3947. FL_OBJECT *
  3948. fl_set_icon_file(FL_OBJECT * ob, const char *f)
  3949. {
  3950.     ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
  3951.  
  3952.     if (f && (!sp->filename || strcmp(f, sp->filename) || !sp->rgba))
  3953.       {
  3954.       free_icon_image(sp);
  3955.       StrReDup(sp->filename, f);
  3956.       sp->rgba = load_icon(sp->filename, &sp->w, &sp->h);
  3957.       }
  3958.     return ob;
  3959. }
  3960.  
  3961. /******************************************************************
  3962.  * Change the associated filename only.
  3963.  ******************************************************************/
  3964. void
  3965. fl_set_icon_info(FL_OBJECT * ob, const char *f)
  3966. {
  3967.     ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
  3968.  
  3969.     if (f)
  3970.     StrReDup(sp->info, f);
  3971.     else
  3972.       {
  3973.       if (sp->info)
  3974.           free(sp->info);
  3975.       sp->info = 0;
  3976.       }
  3977. }
  3978.  
  3979. const char *
  3980. fl_get_icon_info(FL_OBJECT * ob)
  3981. {
  3982.     ICON_SPEC *sp = (ICON_SPEC *) ob->spec;
  3983.     return sp->info;
  3984. }
  3985.  
  3986. /*******************************************************************
  3987.  * END OF RGB_ICON CLASS
  3988.  ******************************************************************} */
  3989.  
  3990. /******************************************************************
  3991.  * Active BITMAP class
  3992.  ******************************************************************{*/
  3993.  
  3994. typedef struct
  3995. {
  3996.     int val;            /* true if pressed          */
  3997.     int col;            /* color shown when focused */
  3998.     int w, h;            /* bitmap size              */
  3999.     char *bits;            /* the actual bitmap       */
  4000. }
  4001. Abitmap_t;
  4002.  
  4003. static void
  4004. ab_init(Abitmap_t * ab)
  4005. {
  4006.     ab->val = ab->w = ab->h = 0;
  4007.     ab->col = FL_BLUE;        /* red is default cursor, look bad */
  4008. }
  4009.  
  4010.  
  4011. static unsigned long thebits[FL_BITMAP_MAXSIZE];
  4012.  
  4013. static void
  4014. draw_bitmap(FL_OBJECT * ob)
  4015. {
  4016.     Abitmap_t *sp = ((Abitmap_t *) (ob->spec));
  4017.     int i, j, k = 0, aoffset;
  4018.     int col;
  4019.     short rgb[2][3], *cc;
  4020.     int xx, yy;            /* position of bitmap */
  4021.  
  4022.     col = (sp->val ? sp->col : ob->col1);
  4023.     if (ob->belowmouse && (col == FL_BLACK || col == FL_INACTIVE))
  4024.     col = sp->col;
  4025.  
  4026.     /* Draw the box */
  4027.     if (ob->boxtype == FL_UP_BOX && sp->val)
  4028.     fl_drw_box(FL_DOWN_BOX, ob->x, ob->y, ob->w, ob->h, ob->col2,
  4029.            FL_ACTIVE_BITMAP_BW);
  4030.     else
  4031.     fl_drw_box(ob->boxtype, ob->x, ob->y, ob->w, ob->h, ob->col2,
  4032.            FL_ACTIVE_BITMAP_BW);
  4033.  
  4034.     fl_drw_text_beside(ob->align, ob->x, ob->y, ob->w, ob->h,
  4035.                ob->lcol, ob->lsize, ob->lstyle, ob->label);
  4036.  
  4037.     if (sp->w == 0)
  4038.     return;
  4039.  
  4040.     cc = rgb[0];
  4041.     fl_getmcolor(ob->col2, cc, cc + 1, cc + 2);
  4042.     cc = rgb[1];
  4043.     fl_getmcolor(col, cc, cc + 1, cc + 2);
  4044.  
  4045.     /* Create the bitmap */
  4046.     for (j = 0; j < sp->h; j++)
  4047.       {
  4048.       aoffset = (sp->h - j - 1) * sp->w;
  4049.       for (i = 0; i < sp->w; i++)
  4050.         {
  4051.         cc = rgb[((sp->bits[k + i / 8] & (1 << (i % 8)))) != 0];
  4052.         thebits[aoffset + i] = 0x10000 * cc[2] + 0x100 * cc[1] + cc[0];
  4053.         }
  4054.       k += (sp->w + 7) / 8;
  4055.       }
  4056.  
  4057.     /* Calculate position and draw bitmap */
  4058.     xx = (int) (ob->x + (ob->w - (float) sp->w) / 2.0);
  4059.     yy = (int) (ob->y + (ob->h - (float) sp->h) / 2.0);
  4060.     lrectwrite(xx, yy, xx - 1 + sp->w, yy - 1 + sp->h, thebits);
  4061. }
  4062.  
  4063. /* ARGSUSED */
  4064. static int
  4065. handle_abitmap(FL_OBJECT * ob, int event,
  4066.            float mx, float my, char key)
  4067. {
  4068.     int oval = 0, nval;
  4069.     Abitmap_t *sp = (Abitmap_t *) ob->spec;
  4070.  
  4071.     switch (event)
  4072.       {
  4073.       case FL_DRAW:
  4074.       draw_bitmap(ob);
  4075.       break;
  4076.       case FL_ENTER:
  4077.       case FL_LEAVE:
  4078.       fl_redraw_object(ob);
  4079.       return 0;
  4080.       case FL_PUSH:
  4081.       oval = sp->val;
  4082.       sp->val = !sp->val;
  4083.       fl_redraw_object(ob);
  4084.       return 0;
  4085.       case FL_RELEASE:
  4086.       if (ob->type == FL_RADIO_BITMAP)
  4087.           return 1;
  4088.       else if (ob->type == FL_PUSH_BITMAP)
  4089.           return (sp->val != oval);
  4090.       else if (sp->val == 0)
  4091.           return 0;
  4092.       sp->val = 0;
  4093.       fl_redraw_object(ob);
  4094.       return 1;
  4095.       case FL_MOUSE:
  4096.       if (ob->type != FL_RADIO_BITMAP)
  4097.         {
  4098.         if (mx < ob->x || mx > (ob->x + ob->w) ||
  4099.             (my < ob->y || my < (ob->y + ob->h)))
  4100.             nval = oval;
  4101.         else
  4102.             nval = !oval;
  4103.  
  4104.         if (sp->val != nval)
  4105.           {
  4106.               sp->val = nval;
  4107.               fl_redraw_object(ob);
  4108.           }
  4109.         }
  4110.       return 0;
  4111.       case FL_FREEMEM:
  4112.       free(ob->spec);
  4113.       break;
  4114.       }
  4115.     return 0;
  4116. }
  4117.  
  4118. static FL_OBJECT *
  4119. create_ab(int objclass, int type, float x, float y, float w, float h,
  4120.       const char *label)
  4121. {
  4122.     FL_OBJECT *ob;
  4123.  
  4124.  
  4125.     ob = fl_make_object(objclass, type, x, y, w, h, label, handle_abitmap);
  4126.  
  4127.     ob->boxtype = FL_ACTIVE_BITMAP_BOXTYPE;
  4128.     ob->col1 = FL_BLACK;
  4129.     ob->col2 = FL_MAGIC1;
  4130.     ob->lcol = FL_BLACK;
  4131.     ob->align = FL_ALIGN_CENTER;
  4132.     ob->active = 1;
  4133.     ob->radio = type == FL_RADIO_BITMAP;
  4134.  
  4135.     ob->spec = (int *) fl_malloc(sizeof(Abitmap_t));
  4136.  
  4137.     /* specific to ab */
  4138.     ab_init((Abitmap_t *) ob->spec);
  4139.     return ob;
  4140. }
  4141.  
  4142. static FL_OBJECT *
  4143. fl_create_active_bitmap(int type, float x, float y, float w, float h,
  4144.             const char *label)
  4145. {
  4146.     return create_ab(FL_ACTIVE_BITMAP, type, x, y, w, h, label);
  4147. }
  4148.  
  4149. FL_OBJECT *
  4150. fl_add_active_bitmap(int type, float x, float y, float w, float h,
  4151.              const char *label)
  4152. {
  4153.     FL_OBJECT *ob;
  4154.  
  4155.     ob = fl_create_active_bitmap(type, x, y, w, h, label);
  4156.     fl_add_object(fl_current_form, ob);
  4157.     return ob;
  4158. }
  4159.  
  4160. int
  4161. fl_get_active_bitmap(FL_OBJECT * ob)
  4162. {
  4163.     return (ob->objclass != FL_ACTIVE_BITMAP ? 0 :
  4164.         ((Abitmap_t *) (ob->spec))->val);
  4165. }
  4166.  
  4167. void
  4168. fl_set_active_bitmap(FL_OBJECT * ob, int y)
  4169. {
  4170.     if (ob->objclass == FL_ACTIVE_BITMAP)
  4171.       {
  4172.       ((Abitmap_t *) (ob->spec))->val = y;
  4173.       if (ob->type == FL_RADIO_BITMAP)
  4174.           ob->pushed = y;
  4175.       }
  4176. }
  4177.  
  4178. FL_OBJECT *
  4179. fl_set_bitmap_bitmap(FL_OBJECT * ob, int w, int h, char *b)
  4180. {
  4181.     Abitmap_t *sp;
  4182.  
  4183.     if (ob && ob->objclass == FL_ACTIVE_BITMAP)
  4184.       {
  4185.       sp = (Abitmap_t *) (ob->spec);
  4186.       sp->w = w;
  4187.       sp->h = h;
  4188.       sp->bits = b;
  4189.       if (w * h > FL_BITMAP_MAXSIZE)
  4190.           sp->h = FL_BITMAP_MAXSIZE / w;
  4191.       fl_redraw_object(ob);
  4192.       }
  4193.     return ob;
  4194. }
  4195.  
  4196. void
  4197. fl_set_active_bitmap_color(FL_OBJECT * ob, int c)
  4198. {
  4199.     ((Abitmap_t *) (ob->spec))->col = c;
  4200. }
  4201.  
  4202. /***************************************************************
  4203.  * END of Active Bitmap Class
  4204.  **************************************************************}*/
  4205.  
  4206.  
  4207. /*******************************************************
  4208.  * Get 2 integers and a flag
  4209.  *******************************************************/
  4210.  
  4211. static void create_form_int2(void);
  4212. static FL_OBJECT *ct1, *ct2, *bobj, *hobj;
  4213. static FL_FORM *input2;
  4214. static FL_OBJECT *int2cancel, *int2ok;
  4215.  
  4216. int
  4217. get2int(const char *p1, int *v1, int cv1i, int cv1f,
  4218.     const char *p2, int *v2, int cv2i, int cv2f,
  4219.     const char *bl1, int *b1, int hindex, int im)
  4220. {
  4221.     int sv1 = *v1, sv2 = *v2, sb1 = b1 ? *b1 : 0;
  4222.     int v1step1, v1step2;
  4223.     int v2step1, v2step2;
  4224.     FL_OBJECT *obj;
  4225.     short val;
  4226.  
  4227.     create_form_int2();
  4228.  
  4229.     ((bl1 && *bl1) ? fl_show_object : fl_hide_object) (bobj);
  4230.     fl_set_button(bobj, *b1);
  4231.  
  4232.     fl_set_object_label(bobj, bl1);
  4233.     get_i_step(cv1i, cv1f, &v1step1, &v1step2);
  4234.     get_i_step(cv2i, cv2f, &v2step1, &v2step2);
  4235.     fl_set_counter_precision(ct1, 0);
  4236.     fl_set_counter_precision(ct2, 0);
  4237.     fl_set_counter_bounds(ct1, cv1i, cv1f);
  4238.     fl_set_counter_bounds(ct2, cv2i, cv2f);
  4239.     fl_set_counter_step(ct1, v1step1, v1step2);
  4240.     fl_set_counter_step(ct2, v2step1, v2step2);
  4241.     fl_set_counter_return(ct1, im);
  4242.     fl_set_counter_return(ct2, im);
  4243.     fl_set_counter_value(ct1, sv1);
  4244.     fl_set_counter_value(ct2, sv2);
  4245.     fl_set_object_label(ct1, p1 ? p1 : "Integer");
  4246.     fl_set_object_label(ct2, p2 ? p2 : "Integer");
  4247.  
  4248.     deactivate_all_forms();
  4249.     set_cursor(bit_show_form(input2, FL_PLACE_MOUSE, 0, "Input2"), CUR_HAND);
  4250.     do
  4251.       {
  4252.       obj = fl_do_forms();
  4253.       if (obj == FL_EVENT)
  4254.           bit_qread(&val);
  4255.       else if (obj == bobj)
  4256.           *b1 = fl_get_button(bobj);
  4257.       else if (obj == hobj)
  4258.           help_cb(0, hindex);
  4259.       }
  4260.     while (obj != int2cancel && obj != int2ok && !im);
  4261.  
  4262.     *v1 = (obj == int2cancel) ? sv1 : fl_get_counter_value(ct1);
  4263.     *v2 = (obj == int2cancel) ? sv2 : fl_get_counter_value(ct2);
  4264.     if (b1)
  4265.       {
  4266.       *b1 = (obj == int2cancel) ? sb1 : fl_get_button(bobj);
  4267.       }
  4268.     fl_activate_all_forms();
  4269.     if (obj == int2cancel || obj == int2ok)
  4270.     bit_hide_form(input2);
  4271.  
  4272.     return obj == int2cancel ? -1 : (obj == int2ok);
  4273. }
  4274.  
  4275. static void
  4276. create_form_int2(void)
  4277. {
  4278.     FL_OBJECT *obj;
  4279.  
  4280.     if (input2)
  4281.     return;
  4282.  
  4283.     input2 = fl_bgn_form(FL_NO_BOX, 330.0, 150.0);
  4284.     obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 330.0, 150.0, "");
  4285.     hobj = fl_add_button(FL_HB, 0.0, 0.0, 330.0, 150.0, "");
  4286.     ct1 = obj = fl_add_counter(FL_NC, 20.0, 90.0, 180.0, 30.0, "");
  4287.     fl_set_object_lsize(obj, 10.0);
  4288.     fl_set_object_align(obj, FL_ALIGN_TOP);
  4289.     ct2 = obj = fl_add_counter(FL_NC, 20.0, 20.0, 180.0, 30.0, "");
  4290.     fl_set_object_lsize(obj, 10.0);
  4291.     fl_set_object_align(obj, FL_ALIGN_TOP);
  4292.     int2cancel = obj = fl_add_button(FL_NB, 230.0, 35.0, 80.0, 25.0, "Cancel");
  4293.     fl_set_object_lsize(obj, 10.0);
  4294.     fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
  4295.     int2ok = obj = fl_add_button(FL_NB, 230.0, 10.0, 80.0, 25.0, "OK");
  4296.     fl_set_object_lsize(obj, 10.0);
  4297.     fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
  4298.     bobj = obj = fl_add_roundbutton(FL_PB, 230.0, 110.0, 30.0, 30.0, "");
  4299.     fl_set_object_lsize(obj, 10.0);
  4300.     fl_end_form();
  4301. }
  4302.